diff options
-rw-r--r-- | cli/global_state.rs | 19 | ||||
-rw-r--r-- | cli/global_timer.rs | 46 | ||||
-rw-r--r-- | cli/main.rs | 2 | ||||
-rw-r--r-- | cli/ops/errors.rs | 2 | ||||
-rw-r--r-- | cli/ops/fetch.rs | 6 | ||||
-rw-r--r-- | cli/ops/fs.rs | 209 | ||||
-rw-r--r-- | cli/ops/fs_events.rs | 5 | ||||
-rw-r--r-- | cli/ops/mod.rs | 10 | ||||
-rw-r--r-- | cli/ops/net.rs | 38 | ||||
-rw-r--r-- | cli/ops/os.rs | 34 | ||||
-rw-r--r-- | cli/ops/permissions.rs | 10 | ||||
-rw-r--r-- | cli/ops/plugin.rs | 6 | ||||
-rw-r--r-- | cli/ops/process.rs | 12 | ||||
-rw-r--r-- | cli/ops/repl.rs | 4 | ||||
-rw-r--r-- | cli/ops/runtime.rs | 10 | ||||
-rw-r--r-- | cli/ops/runtime_compiler.rs | 19 | ||||
-rw-r--r-- | cli/ops/signal.rs | 6 | ||||
-rw-r--r-- | cli/ops/timers.rs | 56 | ||||
-rw-r--r-- | cli/ops/tls.rs | 24 | ||||
-rw-r--r-- | cli/ops/tty.rs | 4 | ||||
-rw-r--r-- | cli/ops/websocket.rs | 11 | ||||
-rw-r--r-- | cli/ops/worker_host.rs | 52 | ||||
-rw-r--r-- | cli/permissions.rs | 10 | ||||
-rw-r--r-- | cli/state.rs | 227 | ||||
-rw-r--r-- | cli/tsc.rs | 34 | ||||
-rw-r--r-- | cli/web_worker.rs | 36 | ||||
-rw-r--r-- | cli/worker.rs | 118 | ||||
-rw-r--r-- | core/modules.rs | 39 | ||||
-rw-r--r-- | core/runtime.rs | 13 | ||||
-rw-r--r-- | op_crates/fetch/lib.rs | 8 |
30 files changed, 551 insertions, 519 deletions
diff --git a/cli/global_state.rs b/cli/global_state.rs index 700909f8f..52bf48593 100644 --- a/cli/global_state.rs +++ b/cli/global_state.rs @@ -10,7 +10,6 @@ use crate::media_type::MediaType; use crate::module_graph::ModuleGraphFile; use crate::module_graph::ModuleGraphLoader; use crate::permissions::Permissions; -use crate::state::exit_unstable; use crate::tsc::CompiledModule; use crate::tsc::TargetLib; use crate::tsc::TsCompiler; @@ -22,6 +21,14 @@ use std::sync::Arc; use std::sync::Mutex; use tokio::sync::Mutex as AsyncMutex; +pub fn exit_unstable(api_name: &str) { + eprintln!( + "Unstable API '{}'. The --unstable flag must be provided.", + api_name + ); + std::process::exit(70); +} + /// This structure represents state of single "deno" program. /// /// It is shared by all created workers (thus V8 isolates). @@ -235,6 +242,16 @@ impl GlobalState { Ok(compiled_module) } + /// Quits the process if the --unstable flag was not provided. + /// + /// This is intentionally a non-recoverable check so that people cannot probe + /// for unstable APIs from stable programs. + pub fn check_unstable(&self, api_name: &str) { + if !self.flags.unstable { + exit_unstable(api_name); + } + } + #[cfg(test)] pub fn mock( argv: Vec<String>, diff --git a/cli/global_timer.rs b/cli/global_timer.rs index bf335bff0..6fad563a2 100644 --- a/cli/global_timer.rs +++ b/cli/global_timer.rs @@ -1,47 +1 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - -//! This module helps deno implement timers. -//! -//! As an optimization, we want to avoid an expensive calls into rust for every -//! setTimeout in JavaScript. Thus in //js/timers.ts a data structure is -//! implemented that calls into Rust for only the smallest timeout. Thus we -//! only need to be able to start and cancel a single timer (or Delay, as Tokio -//! calls it) for an entire Isolate. This is what is implemented here. - -use futures::channel::oneshot; -use futures::future::FutureExt; -use futures::TryFutureExt; -use std::future::Future; -use std::time::Instant; - -#[derive(Default)] -pub struct GlobalTimer { - tx: Option<oneshot::Sender<()>>, -} - -impl GlobalTimer { - pub fn cancel(&mut self) { - if let Some(tx) = self.tx.take() { - tx.send(()).ok(); - } - } - - pub fn new_timeout( - &mut self, - deadline: Instant, - ) -> impl Future<Output = Result<(), ()>> { - if self.tx.is_some() { - self.cancel(); - } - assert!(self.tx.is_none()); - - let (tx, rx) = oneshot::channel(); - self.tx = Some(tx); - - let delay = tokio::time::delay_until(deadline.into()); - let rx = rx - .map_err(|err| panic!("Unexpected error in receiving channel {:?}", err)); - - futures::future::select(delay, rx).then(|_| futures::future::ok(())) - } -} diff --git a/cli/main.rs b/cli/main.rs index 2d80372c7..f45586c61 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -78,9 +78,9 @@ use flags::DenoSubcommand; use flags::Flags; use futures::future::FutureExt; use futures::Future; +use global_state::exit_unstable; use log::Level; use log::LevelFilter; -use state::exit_unstable; use std::env; use std::io::Read; use std::io::Write; diff --git a/cli/ops/errors.rs b/cli/ops/errors.rs index 5012b0db0..6bf0983e2 100644 --- a/cli/ops/errors.rs +++ b/cli/ops/errors.rs @@ -37,7 +37,7 @@ fn op_apply_source_map( args.line_number.into(), args.column_number.into(), &mut mappings_map, - &super::cli_state(state).global_state.ts_compiler, + &super::global_state(state).ts_compiler, ); Ok(json!({ diff --git a/cli/ops/fetch.rs b/cli/ops/fetch.rs index cbfcfb874..54585dc3d 100644 --- a/cli/ops/fetch.rs +++ b/cli/ops/fetch.rs @@ -1,12 +1,12 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::state::CliState; +use crate::permissions::Permissions; pub fn init(rt: &mut deno_core::JsRuntime) { - super::reg_json_async(rt, "op_fetch", deno_fetch::op_fetch::<CliState>); + super::reg_json_async(rt, "op_fetch", deno_fetch::op_fetch::<Permissions>); super::reg_json_async(rt, "op_fetch_read", deno_fetch::op_fetch_read); super::reg_json_sync( rt, "op_create_http_client", - deno_fetch::op_create_http_client::<CliState>, + deno_fetch::op_create_http_client::<Permissions>, ); } diff --git a/cli/ops/fs.rs b/cli/ops/fs.rs index 5189d7099..ad5cc8add 100644 --- a/cli/ops/fs.rs +++ b/cli/ops/fs.rs @@ -2,6 +2,7 @@ // Some deserializer fields are only used on Unix and Windows build fails without it use super::io::std_file_resource; use super::io::{FileMetadata, StreamResource, StreamResourceHolder}; +use crate::permissions::Permissions; use deno_core::error::custom_error; use deno_core::error::type_error; use deno_core::error::AnyError; @@ -151,15 +152,15 @@ fn open_helper( let _ = mode; // avoid unused warning } + let permissions = state.borrow::<Permissions>(); let options = args.options; + if options.read { - let cli_state = super::cli_state(state); - cli_state.check_read(&path)?; + permissions.check_read(&path)?; } if options.write || options.append { - let cli_state = super::cli_state(state); - cli_state.check_write(&path)?; + permissions.check_write(&path)?; } open_options @@ -280,7 +281,7 @@ fn op_fdatasync_sync( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.fdatasync"); } let args: FdatasyncArgs = serde_json::from_value(args)?; @@ -297,7 +298,7 @@ async fn op_fdatasync_async( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - super::cli_state2(&state).check_unstable("Deno.fdatasync"); + super::global_state2(&state).check_unstable("Deno.fdatasync"); let args: FdatasyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; @@ -320,7 +321,7 @@ fn op_fsync_sync( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.fsync"); } let args: FsyncArgs = serde_json::from_value(args)?; @@ -337,7 +338,7 @@ async fn op_fsync_async( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - super::cli_state2(&state).check_unstable("Deno.fsync"); + super::global_state2(&state).check_unstable("Deno.fsync"); let args: FsyncArgs = serde_json::from_value(args)?; let rid = args.rid as u32; @@ -360,7 +361,7 @@ fn op_fstat_sync( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.fstat"); } let args: FstatArgs = serde_json::from_value(args)?; @@ -377,7 +378,7 @@ async fn op_fstat_async( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - super::cli_state2(&state).check_unstable("Deno.fstat"); + super::global_state2(&state).check_unstable("Deno.fstat"); let args: FstatArgs = serde_json::from_value(args)?; let rid = args.rid as u32; @@ -402,7 +403,7 @@ fn op_umask( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.umask"); } let args: UmaskArgs = serde_json::from_value(args)?; @@ -444,8 +445,7 @@ fn op_chdir( ) -> Result<Value, AnyError> { let args: ChdirArgs = serde_json::from_value(args)?; let d = PathBuf::from(&args.directory); - let cli_state = super::cli_state(state); - cli_state.check_read(&d)?; + state.borrow::<Permissions>().check_read(&d)?; set_current_dir(&d)?; Ok(json!({})) } @@ -466,8 +466,7 @@ fn op_mkdir_sync( let args: MkdirArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); let mode = args.mode.unwrap_or(0o777) & 0o777; - let cli_state = super::cli_state(state); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); let mut builder = std::fs::DirBuilder::new(); builder.recursive(args.recursive); @@ -489,7 +488,10 @@ async fn op_mkdir_async( let path = Path::new(&args.path).to_path_buf(); let mode = args.mode.unwrap_or(0o777) & 0o777; - super::cli_state2(&state).check_write(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_write(&path)?; + } tokio::task::spawn_blocking(move || { debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); @@ -523,8 +525,7 @@ fn op_chmod_sync( let path = Path::new(&args.path).to_path_buf(); let mode = args.mode & 0o777; - let cli_state = super::cli_state(state); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; debug!("op_chmod_sync {} {:o}", path.display(), mode); #[cfg(unix)] { @@ -551,7 +552,10 @@ async fn op_chmod_async( let path = Path::new(&args.path).to_path_buf(); let mode = args.mode & 0o777; - super::cli_state2(&state).check_write(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_write(&path)?; + } tokio::task::spawn_blocking(move || { debug!("op_chmod_async {} {:o}", path.display(), mode); @@ -589,8 +593,7 @@ fn op_chown_sync( ) -> Result<Value, AnyError> { let args: ChownArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); - let cli_state = super::cli_state(state); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; debug!( "op_chown_sync {} {:?} {:?}", path.display(), @@ -620,7 +623,10 @@ async fn op_chown_async( let args: ChownArgs = serde_json::from_value(args)?; let path = Path::new(&args.path).to_path_buf(); - super::cli_state2(&state).check_write(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_write(&path)?; + } tokio::task::spawn_blocking(move || { debug!( @@ -661,8 +667,7 @@ fn op_remove_sync( let path = PathBuf::from(&args.path); let recursive = args.recursive; - let cli_state = super::cli_state(state); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; #[cfg(not(unix))] use std::os::windows::prelude::MetadataExt; @@ -705,7 +710,10 @@ async fn op_remove_async( let path = PathBuf::from(&args.path); let recursive = args.recursive; - super::cli_state2(&state).check_write(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_write(&path)?; + } tokio::task::spawn_blocking(move || { #[cfg(not(unix))] @@ -759,9 +767,9 @@ fn op_copy_file_sync( let from = PathBuf::from(&args.from); let to = PathBuf::from(&args.to); - let cli_state = super::cli_state(state); - cli_state.check_read(&from)?; - cli_state.check_write(&to)?; + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&from)?; + permissions.check_write(&to)?; debug!("op_copy_file_sync {} {}", from.display(), to.display()); // On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput @@ -785,9 +793,12 @@ async fn op_copy_file_async( let from = PathBuf::from(&args.from); let to = PathBuf::from(&args.to); - let cli_state = super::cli_state2(&state); - cli_state.check_read(&from)?; - cli_state.check_write(&to)?; + { + let state = state.borrow(); + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&from)?; + permissions.check_write(&to)?; + } debug!("op_copy_file_async {} {}", from.display(), to.display()); tokio::task::spawn_blocking(move || { @@ -879,8 +890,7 @@ fn op_stat_sync( let args: StatArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let lstat = args.lstat; - let cli_state = super::cli_state(state); - cli_state.check_read(&path)?; + state.borrow::<Permissions>().check_read(&path)?; debug!("op_stat_sync {} {}", path.display(), lstat); let metadata = if lstat { std::fs::symlink_metadata(&path)? @@ -899,7 +909,10 @@ async fn op_stat_async( let path = PathBuf::from(&args.path); let lstat = args.lstat; - super::cli_state2(&state).check_read(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_read(&path)?; + } tokio::task::spawn_blocking(move || { debug!("op_stat_async {} {}", path.display(), lstat); @@ -928,10 +941,10 @@ fn op_realpath_sync( let args: RealpathArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - let cli_state = super::cli_state(state); - cli_state.check_read(&path)?; + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&path)?; if path.is_relative() { - cli_state.check_read_blind(¤t_dir()?, "CWD")?; + permissions.check_read_blind(¤t_dir()?, "CWD")?; } debug!("op_realpath_sync {}", path.display()); @@ -954,10 +967,13 @@ async fn op_realpath_async( let args: RealpathArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - let cli_state = super::cli_state2(&state); - cli_state.check_read(&path)?; - if path.is_relative() { - cli_state.check_read_blind(¤t_dir()?, "CWD")?; + { + let state = state.borrow(); + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&path)?; + if path.is_relative() { + permissions.check_read_blind(¤t_dir()?, "CWD")?; + } } tokio::task::spawn_blocking(move || { @@ -990,8 +1006,7 @@ fn op_read_dir_sync( let args: ReadDirArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - let cli_state = super::cli_state(state); - cli_state.check_read(&path)?; + state.borrow::<Permissions>().check_read(&path)?; debug!("op_read_dir_sync {}", path.display()); let entries: Vec<_> = std::fs::read_dir(path)? @@ -1022,7 +1037,10 @@ async fn op_read_dir_async( ) -> Result<Value, AnyError> { let args: ReadDirArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - super::cli_state2(&state).check_read(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_read(&path)?; + } tokio::task::spawn_blocking(move || { debug!("op_read_dir_async {}", path.display()); let entries: Vec<_> = std::fs::read_dir(path)? @@ -1065,10 +1083,10 @@ fn op_rename_sync( let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - let cli_state = super::cli_state(state); - cli_state.check_read(&oldpath)?; - cli_state.check_write(&oldpath)?; - cli_state.check_write(&newpath)?; + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&oldpath)?; + permissions.check_write(&oldpath)?; + permissions.check_write(&newpath)?; debug!("op_rename_sync {} {}", oldpath.display(), newpath.display()); std::fs::rename(&oldpath, &newpath)?; Ok(json!({})) @@ -1083,10 +1101,11 @@ async fn op_rename_async( let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); { - let cli_state = super::cli_state2(&state); - cli_state.check_read(&oldpath)?; - cli_state.check_write(&oldpath)?; - cli_state.check_write(&newpath)?; + let state = state.borrow(); + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&oldpath)?; + permissions.check_write(&oldpath)?; + permissions.check_write(&newpath)?; } tokio::task::spawn_blocking(move || { debug!( @@ -1113,14 +1132,15 @@ fn op_link_sync( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.link"); let args: LinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - cli_state.check_read(&oldpath)?; - cli_state.check_write(&newpath)?; + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&oldpath)?; + permissions.check_write(&newpath)?; debug!("op_link_sync {} {}", oldpath.display(), newpath.display()); std::fs::hard_link(&oldpath, &newpath)?; @@ -1132,15 +1152,19 @@ async fn op_link_async( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - let cli_state = super::cli_state2(&state); + let cli_state = super::global_state2(&state); cli_state.check_unstable("Deno.link"); let args: LinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - cli_state.check_read(&oldpath)?; - cli_state.check_write(&newpath)?; + { + let state = state.borrow(); + let permissions = state.borrow::<Permissions>(); + permissions.check_read(&oldpath)?; + permissions.check_write(&newpath)?; + } tokio::task::spawn_blocking(move || { debug!("op_link_async {} {}", oldpath.display(), newpath.display()); @@ -1172,13 +1196,13 @@ fn op_symlink_sync( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.symlink"); let args: SymlinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - cli_state.check_write(&newpath)?; + state.borrow::<Permissions>().check_write(&newpath)?; debug!( "op_symlink_sync {} {}", @@ -1224,14 +1248,17 @@ async fn op_symlink_async( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - let cli_state = super::cli_state2(&state); + let cli_state = super::global_state2(&state); cli_state.check_unstable("Deno.symlink"); let args: SymlinkArgs = serde_json::from_value(args)?; let oldpath = PathBuf::from(&args.oldpath); let newpath = PathBuf::from(&args.newpath); - cli_state.check_write(&newpath)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_write(&newpath)?; + } tokio::task::spawn_blocking(move || { debug!("op_symlink_async {} {}", oldpath.display(), newpath.display()); @@ -1286,8 +1313,7 @@ fn op_read_link_sync( let args: ReadLinkArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - let cli_state = super::cli_state(state); - cli_state.check_read(&path)?; + state.borrow::<Permissions>().check_read(&path)?; debug!("op_read_link_value {}", path.display()); let target = std::fs::read_link(&path)?.into_os_string(); @@ -1302,7 +1328,10 @@ async fn op_read_link_async( ) -> Result<Value, AnyError> { let args: ReadLinkArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); - super::cli_state2(&state).check_read(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_read(&path)?; + } tokio::task::spawn_blocking(move || { debug!("op_read_link_async {}", path.display()); let target = std::fs::read_link(&path)?.into_os_string(); @@ -1326,7 +1355,7 @@ fn op_ftruncate_sync( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.ftruncate"); } let args: FtruncateArgs = serde_json::from_value(args)?; @@ -1344,7 +1373,7 @@ async fn op_ftruncate_async( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - super::cli_state2(&state).check_unstable("Deno.ftruncate"); + super::global_state2(&state).check_unstable("Deno.ftruncate"); let args: FtruncateArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let len = args.len as u64; @@ -1371,8 +1400,7 @@ fn op_truncate_sync( let path = PathBuf::from(&args.path); let len = args.len; - let cli_state = super::cli_state(state); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; debug!("op_truncate_sync {} {}", path.display(), len); let f = std::fs::OpenOptions::new().write(true).open(&path)?; @@ -1388,7 +1416,10 @@ async fn op_truncate_async( let args: TruncateArgs = serde_json::from_value(args)?; let path = PathBuf::from(&args.path); let len = args.len; - super::cli_state2(&state).check_write(&path)?; + { + let state = state.borrow(); + state.borrow::<Permissions>().check_write(&path)?; + } tokio::task::spawn_blocking(move || { debug!("op_truncate_async {} {}", path.display(), len); let f = std::fs::OpenOptions::new().write(true).open(&path)?; @@ -1463,8 +1494,9 @@ fn op_make_temp_dir_sync( let prefix = args.prefix.map(String::from); let suffix = args.suffix.map(String::from); - let cli_state = super::cli_state(state); - cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + state + .borrow::<Permissions>() + .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. @@ -1492,8 +1524,10 @@ async fn op_make_temp_dir_async( let prefix = args.prefix.map(String::from); let suffix = args.suffix.map(String::from); { - let cli_state = super::cli_state2(&state); - cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + let state = state.borrow(); + state + .borrow::<Permissions>() + .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; } tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. @@ -1525,8 +1559,9 @@ fn op_make_temp_file_sync( let prefix = args.prefix.map(String::from); let suffix = args.suffix.map(String::from); - let cli_state = super::cli_state(state); - cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + state + .borrow::<Permissions>() + .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; // TODO(piscisaureus): use byte vector for paths, not a string. // See https://github.com/denoland/deno/issues/627. @@ -1555,8 +1590,9 @@ async fn op_make_temp_file_async( let suffix = args.suffix.map(String::from); { let state = state.borrow(); - let cli_state = super::cli_state(&state); - cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; + state + .borrow::<Permissions>() + .check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; } tokio::task::spawn_blocking(move || { // TODO(piscisaureus): use byte vector for paths, not a string. @@ -1591,7 +1627,7 @@ fn op_futime_sync( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.futimeSync"); } let args: FutimeArgs = serde_json::from_value(args)?; @@ -1618,7 +1654,7 @@ async fn op_futime_async( _zero_copy: BufVec, ) -> Result<Value, AnyError> { let mut state = state.borrow_mut(); - let cli_state = super::cli_state(&state); + let cli_state = super::global_state(&state); cli_state.check_unstable("Deno.futime"); let args: FutimeArgs = serde_json::from_value(args)?; let rid = args.rid as u32; @@ -1651,7 +1687,7 @@ fn op_utime_sync( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.utime"); let args: UtimeArgs = serde_json::from_value(args)?; @@ -1659,7 +1695,7 @@ fn op_utime_sync( let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; filetime::set_file_times(path, atime, mtime)?; Ok(json!({})) } @@ -1670,7 +1706,7 @@ async fn op_utime_async( _zero_copy: BufVec, ) -> Result<Value, AnyError> { let state = state.borrow(); - let cli_state = super::cli_state(&state); + let cli_state = super::global_state(&state); cli_state.check_unstable("Deno.utime"); let args: UtimeArgs = serde_json::from_value(args)?; @@ -1678,7 +1714,7 @@ async fn op_utime_async( let atime = filetime::FileTime::from_unix_time(args.atime.0, args.atime.1); let mtime = filetime::FileTime::from_unix_time(args.mtime.0, args.mtime.1); - cli_state.check_write(&path)?; + state.borrow::<Permissions>().check_write(&path)?; tokio::task::spawn_blocking(move || { filetime::set_file_times(path, atime, mtime)?; @@ -1694,8 +1730,9 @@ fn op_cwd( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let path = current_dir()?; - let cli_state = super::cli_state(state); - cli_state.check_read_blind(&path, "CWD")?; + state + .borrow::<Permissions>() + .check_read_blind(&path, "CWD")?; let path_str = into_string(path.into_os_string())?; Ok(json!(path_str)) } diff --git a/cli/ops/fs_events.rs b/cli/ops/fs_events.rs index bba68f4e4..a79784c5a 100644 --- a/cli/ops/fs_events.rs +++ b/cli/ops/fs_events.rs @@ -1,5 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::permissions::Permissions; use deno_core::error::bad_resource_id; use deno_core::error::AnyError; use deno_core::BufVec; @@ -91,7 +92,9 @@ fn op_fs_events_open( RecursiveMode::NonRecursive }; for path in &args.paths { - super::cli_state(state).check_read(&PathBuf::from(path))?; + state + .borrow::<Permissions>() + .check_read(&PathBuf::from(path))?; watcher.watch(path, recursive_mode)?; } let resource = FsEventsResource { watcher, receiver }; diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs index 2c8e3472f..3149f147d 100644 --- a/cli/ops/mod.rs +++ b/cli/ops/mod.rs @@ -28,6 +28,7 @@ pub mod web_worker; pub mod websocket; pub mod worker_host; +use crate::global_state::GlobalState; use crate::metrics::metrics_op; use deno_core::error::AnyError; use deno_core::json_op_async; @@ -40,6 +41,7 @@ use serde_json::Value; use std::cell::RefCell; use std::future::Future; use std::rc::Rc; +use std::sync::Arc; pub fn reg_json_async<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F) where @@ -58,12 +60,12 @@ where } /// Helper for extracting the commonly used state. Used for sync ops. -pub fn cli_state(state: &OpState) -> Rc<crate::state::CliState> { - state.borrow::<Rc<crate::state::CliState>>().clone() +pub fn global_state(state: &OpState) -> Arc<GlobalState> { + state.borrow::<Arc<GlobalState>>().clone() } /// Helper for extracting the commonly used state. Used for async ops. -pub fn cli_state2(state: &Rc<RefCell<OpState>>) -> Rc<crate::state::CliState> { +pub fn global_state2(state: &Rc<RefCell<OpState>>) -> Arc<GlobalState> { let state = state.borrow(); - state.borrow::<Rc<crate::state::CliState>>().clone() + state.borrow::<Arc<GlobalState>>().clone() } diff --git a/cli/ops/net.rs b/cli/ops/net.rs index 44229f177..4e35f2247 100644 --- a/cli/ops/net.rs +++ b/cli/ops/net.rs @@ -2,6 +2,7 @@ use crate::ops::io::StreamResource; use crate::ops::io::StreamResourceHolder; +use crate::permissions::Permissions; use crate::resolve_addr::resolve_addr; use deno_core::error::bad_resource; use deno_core::error::bad_resource_id; @@ -189,7 +190,6 @@ async fn op_datagram_send( ) -> Result<Value, AnyError> { assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); let zero_copy = zero_copy[0].clone(); - let cli_state = super::cli_state2(&state); match serde_json::from_value(args)? { SendArgs { @@ -197,7 +197,11 @@ async fn op_datagram_send( transport, transport_args: ArgsEnum::Ip(args), } if transport == "udp" => { - cli_state.check_net(&args.hostname, args.port)?; + { + let s = state.borrow(); + s.borrow::<Permissions>() + .check_net(&args.hostname, args.port)?; + } let addr = resolve_addr(&args.hostname, args.port)?; poll_fn(move |cx| { let mut state = state.borrow_mut(); @@ -220,7 +224,10 @@ async fn op_datagram_send( transport_args: ArgsEnum::Unix(args), } if transport == "unixpacket" => { let address_path = Path::new(&args.path); - cli_state.check_read(&address_path)?; + { + let s = state.borrow(); + s.borrow::<Permissions>().check_read(&address_path)?; + } let mut state = state.borrow_mut(); let resource = state .resource_table @@ -251,13 +258,17 @@ async fn op_connect( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - let cli_state = super::cli_state2(&state); match serde_json::from_value(args)? { ConnectArgs { transport, transport_args: ArgsEnum::Ip(args), } if transport == "tcp" => { - cli_state.check_net(&args.hostname, args.port)?; + { + let state_ = state.borrow(); + state_ + .borrow::<Permissions>() + .check_net(&args.hostname, args.port)?; + } let addr = resolve_addr(&args.hostname, args.port)?; let tcp_stream = TcpStream::connect(&addr).await?; let local_addr = tcp_stream.local_addr()?; @@ -290,8 +301,12 @@ async fn op_connect( transport_args: ArgsEnum::Unix(args), } if transport == "unix" => { let address_path = Path::new(&args.path); + let cli_state = super::global_state2(&state); cli_state.check_unstable("Deno.connect"); - cli_state.check_read(&address_path)?; + { + let state_ = state.borrow(); + state_.borrow::<Permissions>().check_read(&address_path)?; + } let path = args.path; let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?; let local_addr = unix_stream.local_addr()?; @@ -331,7 +346,7 @@ fn op_shutdown( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - super::cli_state(state).check_unstable("Deno.shutdown"); + super::global_state(state).check_unstable("Deno.shutdown"); let args: ShutdownArgs = serde_json::from_value(args)?; @@ -475,7 +490,8 @@ fn op_listen( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); + let permissions = state.borrow::<Permissions>(); match serde_json::from_value(args)? { ListenArgs { transport, @@ -485,7 +501,7 @@ fn op_listen( if transport == "udp" { cli_state.check_unstable("Deno.listenDatagram"); } - cli_state.check_net(&args.hostname, args.port)?; + permissions.check_net(&args.hostname, args.port)?; } let addr = resolve_addr(&args.hostname, args.port)?; let (rid, local_addr) = if transport == "tcp" { @@ -521,8 +537,8 @@ fn op_listen( if transport == "unixpacket" { cli_state.check_unstable("Deno.listenDatagram"); } - cli_state.check_read(&address_path)?; - cli_state.check_write(&address_path)?; + permissions.check_read(&address_path)?; + permissions.check_write(&address_path)?; } let (rid, local_addr) = if transport == "unix" { net_unix::listen_unix(state, &address_path)? diff --git a/cli/ops/os.rs b/cli/ops/os.rs index d47d126ab..42d09da86 100644 --- a/cli/ops/os.rs +++ b/cli/ops/os.rs @@ -1,5 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::permissions::Permissions; use deno_core::error::AnyError; use deno_core::url::Url; use deno_core::OpState; @@ -28,8 +29,9 @@ fn op_exec_path( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let current_exe = env::current_exe().unwrap(); - let cli_state = super::cli_state(state); - cli_state.check_read_blind(¤t_exe, "exec_path")?; + state + .borrow::<Permissions>() + .check_read_blind(¤t_exe, "exec_path")?; // Now apply URL parser to current exe to get fully resolved path, otherwise // we might get `./` and `../` bits in `exec_path` let exe_url = Url::from_file_path(current_exe).unwrap(); @@ -49,8 +51,7 @@ fn op_set_env( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: SetEnv = serde_json::from_value(args)?; - let cli_state = super::cli_state(state); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; env::set_var(args.key, args.value); Ok(json!({})) } @@ -60,8 +61,7 @@ fn op_env( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; let v = env::vars().collect::<HashMap<String, String>>(); Ok(json!(v)) } @@ -77,8 +77,7 @@ fn op_get_env( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: GetEnv = serde_json::from_value(args)?; - let cli_state = super::cli_state(state); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; let r = match env::var(args.key) { Err(env::VarError::NotPresent) => json!([]), v => json!([v?]), @@ -97,8 +96,7 @@ fn op_delete_env( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: DeleteEnv = serde_json::from_value(args)?; - let cli_state = super::cli_state(state); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; env::remove_var(args.key); Ok(json!({})) } @@ -122,9 +120,9 @@ fn op_loadavg( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.loadavg"); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; match sys_info::loadavg() { Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])), Err(_) => Ok(json!([0f64, 0f64, 0f64])), @@ -136,9 +134,9 @@ fn op_hostname( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.hostname"); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string()); Ok(json!(hostname)) } @@ -148,9 +146,9 @@ fn op_os_release( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.osRelease"); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; let release = sys_info::os_release().unwrap_or_else(|_| "".to_string()); Ok(json!(release)) } @@ -160,9 +158,9 @@ fn op_system_memory_info( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.systemMemoryInfo"); - cli_state.check_env()?; + state.borrow::<Permissions>().check_env()?; match sys_info::mem_info() { Ok(info) => Ok(json!({ "total": info.total, diff --git a/cli/ops/permissions.rs b/cli/ops/permissions.rs index 2cdb03e31..54dda78bc 100644 --- a/cli/ops/permissions.rs +++ b/cli/ops/permissions.rs @@ -1,5 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::permissions::Permissions; use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::OpState; @@ -27,8 +28,7 @@ pub fn op_query_permission( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: PermissionArgs = serde_json::from_value(args)?; - let cli_state = super::cli_state(state); - let permissions = cli_state.permissions.borrow(); + let permissions = state.borrow::<Permissions>(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { "read" => permissions.query_read(&path.as_deref().map(Path::new)), @@ -54,8 +54,7 @@ pub fn op_revoke_permission( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: PermissionArgs = serde_json::from_value(args)?; - let cli_state = super::cli_state(state); - let mut permissions = cli_state.permissions.borrow_mut(); + let permissions = state.borrow_mut::<Permissions>(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { "read" => permissions.revoke_read(&path.as_deref().map(Path::new)), @@ -81,8 +80,7 @@ pub fn op_request_permission( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let args: PermissionArgs = serde_json::from_value(args)?; - let cli_state = super::cli_state(state); - let permissions = &mut cli_state.permissions.borrow_mut(); + let permissions = state.borrow_mut::<Permissions>(); let path = args.path.as_deref(); let perm = match args.name.as_ref() { "read" => permissions.request_read(&path.as_deref().map(Path::new)), diff --git a/cli/ops/plugin.rs b/cli/ops/plugin.rs index e0081ce09..c862fb674 100644 --- a/cli/ops/plugin.rs +++ b/cli/ops/plugin.rs @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::metrics::metrics_op; +use crate::permissions::Permissions; use deno_core::error::AnyError; use deno_core::plugin_api; use deno_core::BufVec; @@ -39,9 +40,10 @@ pub fn op_open_plugin( let args: OpenPluginArgs = serde_json::from_value(args)?; let filename = PathBuf::from(&args.filename); - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.openPlugin"); - cli_state.check_plugin(&filename)?; + let permissions = state.borrow::<Permissions>(); + permissions.check_plugin(&filename)?; debug!("Loading Plugin: {:#?}", filename); let plugin_lib = Library::open(filename).map(Rc::new)?; diff --git a/cli/ops/process.rs b/cli/ops/process.rs index 3a7db8249..5099889cd 100644 --- a/cli/ops/process.rs +++ b/cli/ops/process.rs @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use super::io::{std_file_resource, StreamResource, StreamResourceHolder}; +use crate::permissions::Permissions; use crate::signal::kill; use deno_core::error::bad_resource_id; use deno_core::error::type_error; @@ -68,7 +69,7 @@ fn op_run( _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { let run_args: RunArgs = serde_json::from_value(args)?; - super::cli_state(state).check_run()?; + state.borrow::<Permissions>().check_run()?; let args = run_args.cmd; let env = run_args.env; @@ -178,7 +179,10 @@ async fn op_run_status( let args: RunStatusArgs = serde_json::from_value(args)?; let rid = args.rid as u32; - super::cli_state2(&state).check_run()?; + { + let s = state.borrow(); + s.borrow::<Permissions>().check_run()?; + } let run_status = poll_fn(|cx| { let mut state = state.borrow_mut(); @@ -221,9 +225,9 @@ fn op_kill( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); cli_state.check_unstable("Deno.kill"); - cli_state.check_run()?; + state.borrow::<Permissions>().check_run()?; let args: KillArgs = serde_json::from_value(args)?; kill(args.pid, args.signo)?; diff --git a/cli/ops/repl.rs b/cli/ops/repl.rs index d2fe5ebe9..c87f7dc5c 100644 --- a/cli/ops/repl.rs +++ b/cli/ops/repl.rs @@ -35,8 +35,8 @@ fn op_repl_start( let args: ReplStartArgs = serde_json::from_value(args)?; debug!("op_repl_start {}", args.history_file); let history_path = { - let cli_state = super::cli_state(state); - repl::history_path(&cli_state.global_state.dir, &args.history_file) + let cli_state = super::global_state(state); + repl::history_path(&cli_state.dir, &args.history_file) }; let repl = repl::Repl::new(history_path); let resource = ReplResource(Arc::new(Mutex::new(repl))); diff --git a/cli/ops/runtime.rs b/cli/ops/runtime.rs index 4c5775bcd..27f2dc8c5 100644 --- a/cli/ops/runtime.rs +++ b/cli/ops/runtime.rs @@ -2,6 +2,7 @@ use crate::colors; use crate::metrics::Metrics; +use crate::permissions::Permissions; use crate::version; use crate::DenoSubcommand; use deno_core::error::AnyError; @@ -22,7 +23,7 @@ fn op_start( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let gs = &super::cli_state(state).global_state; + let gs = &super::global_state(state); Ok(json!({ // TODO(bartlomieju): `cwd` field is not used in JS, remove? @@ -47,12 +48,13 @@ fn op_main_module( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); - let main = &cli_state.main_module.to_string(); + let main = state.borrow::<ModuleSpecifier>().to_string(); let main_url = ModuleSpecifier::resolve_url_or_path(&main)?; if main_url.as_url().scheme() == "file" { let main_path = std::env::current_dir().unwrap().join(main_url.to_string()); - cli_state.check_read_blind(&main_path, "main_module")?; + state + .borrow::<Permissions>() + .check_read_blind(&main_path, "main_module")?; } Ok(json!(&main)) } diff --git a/cli/ops/runtime_compiler.rs b/cli/ops/runtime_compiler.rs index 708a60cfa..f2839585c 100644 --- a/cli/ops/runtime_compiler.rs +++ b/cli/ops/runtime_compiler.rs @@ -1,5 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::permissions::Permissions; use crate::tsc::runtime_bundle; use crate::tsc::runtime_compile; use crate::tsc::runtime_transpile; @@ -32,11 +33,14 @@ async fn op_compile( args: Value, _data: BufVec, ) -> Result<Value, AnyError> { - let cli_state = super::cli_state2(&state); + let cli_state = super::global_state2(&state); cli_state.check_unstable("Deno.compile"); let args: CompileArgs = serde_json::from_value(args)?; - let global_state = cli_state.global_state.clone(); - let permissions = cli_state.permissions.borrow().clone(); + let global_state = cli_state.clone(); + let permissions = { + let state = state.borrow(); + state.borrow::<Permissions>().clone() + }; let fut = if args.bundle { runtime_bundle( &global_state, @@ -71,11 +75,14 @@ async fn op_transpile( args: Value, _data: BufVec, ) -> Result<Value, AnyError> { - let cli_state = super::cli_state2(&state); + let cli_state = super::global_state2(&state); cli_state.check_unstable("Deno.transpile"); let args: TranspileArgs = serde_json::from_value(args)?; - let global_state = cli_state.global_state.clone(); - let permissions = cli_state.permissions.borrow().clone(); + let global_state = cli_state.clone(); + let permissions = { + let state = state.borrow(); + state.borrow::<Permissions>().clone() + }; let result = runtime_transpile(&global_state, permissions, &args.sources, &args.options) .await?; diff --git a/cli/ops/signal.rs b/cli/ops/signal.rs index a731a72aa..3f4c5c8ee 100644 --- a/cli/ops/signal.rs +++ b/cli/ops/signal.rs @@ -48,7 +48,7 @@ fn op_signal_bind( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - super::cli_state(state).check_unstable("Deno.signal"); + super::global_state(state).check_unstable("Deno.signal"); let args: BindSignalArgs = serde_json::from_value(args)?; let rid = state.resource_table.add( "signal", @@ -68,7 +68,7 @@ async fn op_signal_poll( args: Value, _zero_copy: BufVec, ) -> Result<Value, AnyError> { - super::cli_state2(&state).check_unstable("Deno.signal"); + super::global_state2(&state).check_unstable("Deno.signal"); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; @@ -92,7 +92,7 @@ pub fn op_signal_unbind( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - super::cli_state(state).check_unstable("Deno.signal"); + super::global_state(state).check_unstable("Deno.signal"); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let resource = state.resource_table.get_mut::<SignalStreamResource>(rid); diff --git a/cli/ops/timers.rs b/cli/ops/timers.rs index e52bb5b0e..a3aef3fef 100644 --- a/cli/ops/timers.rs +++ b/cli/ops/timers.rs @@ -1,17 +1,61 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::global_timer::GlobalTimer; +//! This module helps deno implement timers. +//! +//! As an optimization, we want to avoid an expensive calls into rust for every +//! setTimeout in JavaScript. Thus in //js/timers.ts a data structure is +//! implemented that calls into Rust for only the smallest timeout. Thus we +//! only need to be able to start and cancel a single timer (or Delay, as Tokio +//! calls it) for an entire Isolate. This is what is implemented here. + +use crate::permissions::Permissions; use deno_core::error::AnyError; use deno_core::BufVec; use deno_core::OpState; use deno_core::ZeroCopyBuf; -use futures::future::FutureExt; +use futures::channel::oneshot; +use futures::FutureExt; +use futures::TryFutureExt; use serde::Deserialize; use serde_json::Value; use std::cell::RefCell; +use std::future::Future; use std::rc::Rc; use std::time::Duration; use std::time::Instant; +pub type StartTime = Instant; + +#[derive(Default)] +pub struct GlobalTimer { + tx: Option<oneshot::Sender<()>>, +} + +impl GlobalTimer { + pub fn cancel(&mut self) { + if let Some(tx) = self.tx.take() { + tx.send(()).ok(); + } + } + + pub fn new_timeout( + &mut self, + deadline: Instant, + ) -> impl Future<Output = Result<(), ()>> { + if self.tx.is_some() { + self.cancel(); + } + assert!(self.tx.is_none()); + + let (tx, rx) = oneshot::channel(); + self.tx = Some(tx); + + let delay = tokio::time::delay_until(deadline.into()); + let rx = rx + .map_err(|err| panic!("Unexpected error in receiving channel {:?}", err)); + + futures::future::select(delay, rx).then(|_| futures::future::ok(())) + } +} pub fn init(rt: &mut deno_core::JsRuntime) { super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop); @@ -61,15 +105,15 @@ fn op_now( _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); - let seconds = cli_state.start_time.elapsed().as_secs(); - let mut subsec_nanos = cli_state.start_time.elapsed().subsec_nanos(); + let start_time = state.borrow::<StartTime>(); + let seconds = start_time.elapsed().as_secs(); + let mut subsec_nanos = start_time.elapsed().subsec_nanos(); let reduced_time_precision = 2_000_000; // 2ms in nanoseconds // If the permission is not enabled // Round the nano result on 2 milliseconds // see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision - if cli_state.check_hrtime().is_err() { + if state.borrow::<Permissions>().check_hrtime().is_err() { subsec_nanos -= subsec_nanos % reduced_time_precision; } diff --git a/cli/ops/tls.rs b/cli/ops/tls.rs index 38b18077d..448e33a9d 100644 --- a/cli/ops/tls.rs +++ b/cli/ops/tls.rs @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use super::io::{StreamResource, StreamResourceHolder}; +use crate::permissions::Permissions; use crate::resolve_addr::resolve_addr; use deno_core::error::bad_resource; use deno_core::error::bad_resource_id; @@ -72,11 +73,13 @@ async fn op_start_tls( domain.push_str("localhost"); } { - let cli_state = super::cli_state2(&state); + let cli_state = super::global_state2(&state); cli_state.check_unstable("Deno.startTls"); - cli_state.check_net(&domain, 0)?; + let s = state.borrow(); + let permissions = s.borrow::<Permissions>(); + permissions.check_net(&domain, 0)?; if let Some(path) = cert_file.clone() { - cli_state.check_read(Path::new(&path))?; + permissions.check_read(Path::new(&path))?; } } let mut resource_holder = { @@ -143,10 +146,11 @@ async fn op_connect_tls( let args: ConnectTLSArgs = serde_json::from_value(args)?; let cert_file = args.cert_file.clone(); { - let cli_state = super::cli_state2(&state); - cli_state.check_net(&args.hostname, args.port)?; + let s = state.borrow(); + let permissions = s.borrow::<Permissions>(); + permissions.check_net(&args.hostname, args.port)?; if let Some(path) = cert_file.clone() { - cli_state.check_read(Path::new(&path))?; + permissions.check_read(Path::new(&path))?; } } let mut domain = args.hostname.clone(); @@ -318,10 +322,10 @@ fn op_listen_tls( let cert_file = args.cert_file; let key_file = args.key_file; { - let cli_state = super::cli_state(state); - cli_state.check_net(&args.hostname, args.port)?; - cli_state.check_read(Path::new(&cert_file))?; - cli_state.check_read(Path::new(&key_file))?; + let permissions = state.borrow::<Permissions>(); + permissions.check_net(&args.hostname, args.port)?; + permissions.check_read(Path::new(&cert_file))?; + permissions.check_read(Path::new(&key_file))?; } let mut config = ServerConfig::new(NoClientAuth::new()); config diff --git a/cli/ops/tty.rs b/cli/ops/tty.rs index 54ebcada6..410256163 100644 --- a/cli/ops/tty.rs +++ b/cli/ops/tty.rs @@ -62,7 +62,7 @@ fn op_set_raw( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - super::cli_state(state).check_unstable("Deno.setRaw"); + super::global_state(state).check_unstable("Deno.setRaw"); let args: SetRawArgs = serde_json::from_value(args)?; let rid = args.rid; @@ -273,7 +273,7 @@ fn op_console_size( args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - super::cli_state(state).check_unstable("Deno.consoleSize"); + super::global_state(state).check_unstable("Deno.consoleSize"); let args: ConsoleSizeArgs = serde_json::from_value(args)?; let rid = args.rid; diff --git a/cli/ops/websocket.rs b/cli/ops/websocket.rs index 5126b93c0..e16ce258c 100644 --- a/cli/ops/websocket.rs +++ b/cli/ops/websocket.rs @@ -1,5 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. +use crate::permissions::Permissions; use core::task::Poll; use deno_core::error::bad_resource_id; use deno_core::error::type_error; @@ -55,10 +56,14 @@ pub async fn op_ws_create( _bufs: BufVec, ) -> Result<Value, AnyError> { let args: CreateArgs = serde_json::from_value(args)?; + { + let s = state.borrow(); + s.borrow::<Permissions>() + .check_net_url(&url::Url::parse(&args.url)?)?; + } let ca_file = { - let cli_state = super::cli_state2(&state); - cli_state.check_net_url(&url::Url::parse(&args.url)?)?; - cli_state.global_state.flags.ca_file.clone() + let cli_state = super::global_state2(&state); + cli_state.flags.ca_file.clone() }; let uri: Uri = args.url.parse()?; let request = Request::builder() diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index deaf6a06b..f7b981c14 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -17,6 +17,7 @@ use futures::future::FutureExt; use serde::Deserialize; use serde_json::Value; use std::cell::RefCell; +use std::collections::HashMap; use std::convert::From; use std::rc::Rc; use std::sync::Arc; @@ -33,6 +34,9 @@ pub fn init(rt: &mut deno_core::JsRuntime) { super::reg_json_async(rt, "op_host_get_message", op_host_get_message); } +pub type WorkersTable = HashMap<u32, (JoinHandle<()>, WebWorkerHandle)>; +pub type WorkerId = u32; + fn create_web_worker( worker_id: u32, name: String, @@ -41,13 +45,13 @@ fn create_web_worker( specifier: ModuleSpecifier, has_deno_namespace: bool, ) -> Result<WebWorker, AnyError> { - let cli_state = crate::state::CliState::new_for_worker( - global_state, - Some(permissions), + let mut worker = WebWorker::new( + name.clone(), + permissions, specifier, - )?; - - let mut worker = WebWorker::new(name.clone(), &cli_state, has_deno_namespace); + global_state.clone(), + has_deno_namespace, + ); if has_deno_namespace { let state = worker.isolate.op_state(); @@ -178,7 +182,7 @@ fn op_create_worker( args: Value, _data: &mut [ZeroCopyBuf], ) -> Result<Value, AnyError> { - let cli_state = super::cli_state(state); + let cli_state = super::global_state(state); let args: CreateWorkerArgs = serde_json::from_value(args)?; let specifier = args.specifier.clone(); @@ -192,10 +196,9 @@ fn op_create_worker( if use_deno_namespace { cli_state.check_unstable("Worker.deno"); } - let global_state = cli_state.global_state.clone(); - let permissions = cli_state.permissions.borrow().clone(); - let worker_id = cli_state.next_worker_id.get(); - cli_state.next_worker_id.set(worker_id + 1); + let permissions = state.borrow::<Permissions>().clone(); + let worker_id = state.take::<WorkerId>(); + state.put::<WorkerId>(worker_id + 1); let module_specifier = ModuleSpecifier::resolve_url(&specifier)?; let worker_name = args_name.unwrap_or_else(|| "".to_string()); @@ -203,7 +206,7 @@ fn op_create_worker( let (join_handle, worker_handle) = run_worker_thread( worker_id, worker_name, - &global_state, + &cli_state, permissions, module_specifier, use_deno_namespace, @@ -211,10 +214,8 @@ fn op_create_worker( )?; // At this point all interactions with worker happen using thread // safe handler returned from previous function call - let cli_state = super::cli_state(state); - cli_state - .workers - .borrow_mut() + state + .borrow_mut::<WorkersTable>() .insert(worker_id, (join_handle, worker_handle)); Ok(json!({ "id": worker_id })) @@ -232,10 +233,8 @@ fn op_host_terminate_worker( ) -> Result<Value, AnyError> { let args: WorkerArgs = serde_json::from_value(args)?; let id = args.id as u32; - let cli_state = super::cli_state(state); - let (join_handle, worker_handle) = cli_state - .workers - .borrow_mut() + let (join_handle, worker_handle) = state + .borrow_mut::<WorkersTable>() .remove(&id) .expect("No worker handle found"); worker_handle.terminate(); @@ -301,10 +300,10 @@ async fn op_host_get_message( ) -> Result<Value, AnyError> { let args: WorkerArgs = serde_json::from_value(args)?; let id = args.id as u32; - let cli_state = super::cli_state2(&state); let worker_handle = { - let workers_table = cli_state.workers.borrow(); + let s = state.borrow(); + let workers_table = s.borrow::<WorkersTable>(); let maybe_handle = workers_table.get(&id); if let Some(handle) = maybe_handle { handle.1.clone() @@ -318,8 +317,9 @@ async fn op_host_get_message( Some(event) => { // Terminal error means that worker should be removed from worker table. if let WorkerEvent::TerminalError(_) = &event { + let mut s = state.borrow_mut(); if let Some((join_handle, mut worker_handle)) = - cli_state.workers.borrow_mut().remove(&id) + s.borrow_mut::<WorkersTable>().remove(&id) { worker_handle.sender.close_channel(); join_handle.join().expect("Worker thread panicked"); @@ -329,7 +329,8 @@ async fn op_host_get_message( } None => { // Worker shuts down - let mut workers = cli_state.workers.borrow_mut(); + let mut s = state.borrow_mut(); + let workers = s.borrow_mut::<WorkersTable>(); // Try to remove worker from workers table - NOTE: `Worker.terminate()` might have been called // already meaning that we won't find worker in table - in that case ignore. if let Some((join_handle, mut worker_handle)) = workers.remove(&id) { @@ -354,8 +355,7 @@ fn op_host_post_message( let msg = Vec::from(&*data[0]).into_boxed_slice(); debug!("post message to worker {}", id); - let cli_state = super::cli_state(state); - let workers = cli_state.workers.borrow(); + let workers = state.borrow::<WorkersTable>(); let worker_handle = workers[&id].1.clone(); worker_handle.post_message(msg)?; Ok(json!({})) diff --git a/cli/permissions.rs b/cli/permissions.rs index 1864e4f37..06a33096f 100644 --- a/cli/permissions.rs +++ b/cli/permissions.rs @@ -626,6 +626,16 @@ impl Permissions { } } +impl deno_fetch::FetchPermissions for Permissions { + fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> { + Permissions::check_net_url(self, url) + } + + fn check_read(&self, p: &PathBuf) -> Result<(), AnyError> { + Permissions::check_read(self, p) + } +} + /// Shows the permission prompt and returns the answer according to the user input. /// This loops until the user gives the proper input. #[cfg(not(test))] diff --git a/cli/state.rs b/cli/state.rs index 37352e263..dcf540d09 100644 --- a/cli/state.rs +++ b/cli/state.rs @@ -1,58 +1,49 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -use crate::file_fetcher::SourceFileFetcher; use crate::global_state::GlobalState; use crate::import_map::ImportMap; use crate::permissions::Permissions; use crate::tsc::TargetLib; -use crate::web_worker::WebWorkerHandle; use deno_core::error::AnyError; -use deno_core::url; use deno_core::ModuleLoadId; use deno_core::ModuleLoader; use deno_core::ModuleSpecifier; +use deno_core::OpState; use futures::future::FutureExt; use futures::Future; -use std::cell::Cell; use std::cell::RefCell; -use std::collections::HashMap; -use std::path::Path; -use std::path::PathBuf; use std::pin::Pin; use std::rc::Rc; use std::str; use std::sync::Arc; -use std::thread::JoinHandle; -use std::time::Instant; -// This is named "CliState" instead of just "State" to avoid confusion with all -// other state structs (GlobalState, OpState, GothamState). -// TODO(ry) Many of the items in this struct should be moved out and into -// OpState, removing redundant RefCell wrappers if possible. -pub struct CliState { - pub global_state: Arc<GlobalState>, - pub permissions: RefCell<Permissions>, - pub main_module: ModuleSpecifier, +pub struct CliModuleLoader { /// When flags contains a `.import_map_path` option, the content of the /// import map file will be resolved and set. pub import_map: Option<ImportMap>, - pub workers: RefCell<HashMap<u32, (JoinHandle<()>, WebWorkerHandle)>>, - pub next_worker_id: Cell<u32>, - pub start_time: Instant, pub target_lib: TargetLib, pub is_main: bool, - pub is_internal: bool, } -pub fn exit_unstable(api_name: &str) { - eprintln!( - "Unstable API '{}'. The --unstable flag must be provided.", - api_name - ); - std::process::exit(70); +impl CliModuleLoader { + pub fn new(maybe_import_map: Option<ImportMap>) -> Rc<Self> { + Rc::new(CliModuleLoader { + import_map: maybe_import_map, + target_lib: TargetLib::Main, + is_main: true, + }) + } + + pub fn new_for_worker() -> Rc<Self> { + Rc::new(CliModuleLoader { + import_map: None, + target_lib: TargetLib::Worker, + is_main: false, + }) + } } -impl ModuleLoader for CliState { +impl ModuleLoader for CliModuleLoader { fn resolve( &self, specifier: &str, @@ -75,13 +66,17 @@ impl ModuleLoader for CliState { fn load( &self, + op_state: Rc<RefCell<OpState>>, module_specifier: &ModuleSpecifier, maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, ) -> Pin<Box<deno_core::ModuleSourceFuture>> { let module_specifier = module_specifier.to_owned(); let module_url_specified = module_specifier.to_string(); - let global_state = self.global_state.clone(); + let global_state = { + let state = op_state.borrow(); + state.borrow::<Arc<GlobalState>>().clone() + }; // TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param let fut = async move { @@ -102,6 +97,7 @@ impl ModuleLoader for CliState { fn prepare_load( &self, + op_state: Rc<RefCell<OpState>>, _load_id: ModuleLoadId, module_specifier: &ModuleSpecifier, maybe_referrer: Option<String>, @@ -110,15 +106,19 @@ impl ModuleLoader for CliState { let module_specifier = module_specifier.clone(); let target_lib = self.target_lib.clone(); let maybe_import_map = self.import_map.clone(); + let state = op_state.borrow(); + // Only "main" module is loaded without permission check, // ie. module that is associated with "is_main" state // and is not a dynamic import. let permissions = if self.is_main && !is_dyn_import { Permissions::allow_all() } else { - self.permissions.borrow().clone() + state.borrow::<Permissions>().clone() }; - let global_state = self.global_state.clone(); + let global_state = state.borrow::<Arc<GlobalState>>().clone(); + drop(state); + // TODO(bartlomieju): I'm not sure if it's correct to ignore // bad referrer - this is the case for `Deno.core.evalContext()` where // `ref_str` is `<unknown>`. @@ -144,168 +144,3 @@ impl ModuleLoader for CliState { .boxed_local() } } - -impl CliState { - /// If `shared_permission` is None then permissions from globa state are used. - pub fn new( - global_state: &Arc<GlobalState>, - shared_permissions: Option<Permissions>, - main_module: ModuleSpecifier, - maybe_import_map: Option<ImportMap>, - is_internal: bool, - ) -> Result<Rc<Self>, AnyError> { - let state = CliState { - global_state: global_state.clone(), - main_module, - permissions: shared_permissions - .unwrap_or_else(|| global_state.permissions.clone()) - .into(), - import_map: maybe_import_map, - workers: Default::default(), - next_worker_id: Default::default(), - start_time: Instant::now(), - target_lib: TargetLib::Main, - is_main: true, - is_internal, - }; - Ok(Rc::new(state)) - } - - /// If `shared_permission` is None then permissions from globa state are used. - pub fn new_for_worker( - global_state: &Arc<GlobalState>, - shared_permissions: Option<Permissions>, - main_module: ModuleSpecifier, - ) -> Result<Rc<Self>, AnyError> { - let state = CliState { - global_state: global_state.clone(), - main_module, - permissions: shared_permissions - .unwrap_or_else(|| global_state.permissions.clone()) - .into(), - import_map: None, - workers: Default::default(), - next_worker_id: Default::default(), - start_time: Instant::now(), - target_lib: TargetLib::Worker, - is_main: false, - is_internal: false, - }; - Ok(Rc::new(state)) - } - - #[inline] - pub fn check_read(&self, path: &Path) -> Result<(), AnyError> { - self.permissions.borrow().check_read(path) - } - - /// As `check_read()`, but permission error messages will anonymize the path - /// by replacing it with the given `display`. - #[inline] - pub fn check_read_blind( - &self, - path: &Path, - display: &str, - ) -> Result<(), AnyError> { - self.permissions.borrow().check_read_blind(path, display) - } - - #[inline] - pub fn check_write(&self, path: &Path) -> Result<(), AnyError> { - self.permissions.borrow().check_write(path) - } - - #[inline] - pub fn check_env(&self) -> Result<(), AnyError> { - self.permissions.borrow().check_env() - } - - #[inline] - pub fn check_net(&self, hostname: &str, port: u16) -> Result<(), AnyError> { - self.permissions.borrow().check_net(hostname, port) - } - - #[inline] - pub fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> { - self.permissions.borrow().check_net_url(url) - } - - #[inline] - pub fn check_run(&self) -> Result<(), AnyError> { - self.permissions.borrow().check_run() - } - - #[inline] - pub fn check_hrtime(&self) -> Result<(), AnyError> { - self.permissions.borrow().check_hrtime() - } - - #[inline] - pub fn check_plugin(&self, filename: &Path) -> Result<(), AnyError> { - self.permissions.borrow().check_plugin(filename) - } - - pub fn check_dyn_import( - &self, - module_specifier: &ModuleSpecifier, - ) -> Result<(), AnyError> { - let u = module_specifier.as_url(); - // TODO(bartlomieju): temporary fix to prevent hitting `unreachable` - // statement that is actually reachable... - SourceFileFetcher::check_if_supported_scheme(u)?; - - match u.scheme() { - "http" | "https" => { - self.check_net_url(u)?; - Ok(()) - } - "file" => { - let path = u - .to_file_path() - .unwrap() - .into_os_string() - .into_string() - .unwrap(); - self.check_read(Path::new(&path))?; - Ok(()) - } - _ => unreachable!(), - } - } - - #[cfg(test)] - pub fn mock(main_module: &str) -> Rc<Self> { - let module_specifier = ModuleSpecifier::resolve_url_or_path(main_module) - .expect("Invalid entry module"); - CliState::new( - &GlobalState::mock(vec!["deno".to_string()], None), - None, - module_specifier, - None, - false, - ) - .unwrap() - } - - /// Quits the process if the --unstable flag was not provided. - /// - /// This is intentionally a non-recoverable check so that people cannot probe - /// for unstable APIs from stable programs. - pub fn check_unstable(&self, api_name: &str) { - // TODO(ry) Maybe use IsolateHandle::terminate_execution here to provide a - // stack trace in JS. - if !self.global_state.flags.unstable { - exit_unstable(api_name); - } - } -} - -impl deno_fetch::FetchPermissions for CliState { - fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> { - CliState::check_net_url(self, url) - } - - fn check_read(&self, p: &PathBuf) -> Result<(), AnyError> { - CliState::check_read(self, p) - } -} diff --git a/cli/tsc.rs b/cli/tsc.rs index 1e75b7041..c4102cc42 100644 --- a/cli/tsc.rs +++ b/cli/tsc.rs @@ -18,7 +18,7 @@ use crate::module_graph::ModuleGraphLoader; use crate::ops; use crate::permissions::Permissions; use crate::source_maps::SourceMapGetter; -use crate::state::CliState; +use crate::state::CliModuleLoader; use crate::tsc_config; use crate::version; use crate::worker::Worker; @@ -48,7 +48,6 @@ use std::ops::DerefMut; use std::path::Path; use std::path::PathBuf; use std::pin::Pin; -use std::rc::Rc; use std::str; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -132,9 +131,25 @@ pub struct CompilerWorker { } impl CompilerWorker { - pub fn new(name: String, state: &Rc<CliState>) -> Self { - let mut worker = - Worker::new(name, Some(js::compiler_isolate_init()), state); + pub fn new( + name: String, + permissions: Permissions, + global_state: Arc<GlobalState>, + ) -> Self { + let main_module = + ModuleSpecifier::resolve_url_or_path("./$deno$compiler.ts").unwrap(); + // TODO(bartlomieju): compiler worker shouldn't require any loader/state + let loader = CliModuleLoader::new(None); + let mut worker = Worker::new( + name, + Some(js::compiler_isolate_init()), + permissions, + main_module, + global_state, + loader, + false, + true, + ); let response = Arc::new(Mutex::new(None)); ops::runtime::init(&mut worker); ops::errors::init(&mut worker); @@ -215,17 +230,12 @@ fn create_compiler_worker( global_state: &Arc<GlobalState>, permissions: Permissions, ) -> CompilerWorker { - let entry_point = - ModuleSpecifier::resolve_url_or_path("./$deno$compiler.ts").unwrap(); - let worker_state = - CliState::new(&global_state, Some(permissions), entry_point, None, true) - .expect("Unable to create worker state"); - // TODO(bartlomieju): this metric is never used anywhere // Count how many times we start the compiler worker. global_state.compiler_starts.fetch_add(1, Ordering::SeqCst); - let mut worker = CompilerWorker::new("TS".to_string(), &worker_state); + let mut worker = + CompilerWorker::new("TS".to_string(), permissions, global_state.clone()); worker .execute("globalThis.bootstrapCompilerRuntime()") .unwrap(); diff --git a/cli/web_worker.rs b/cli/web_worker.rs index a4d0fe24c..75704d924 100644 --- a/cli/web_worker.rs +++ b/cli/web_worker.rs @@ -1,13 +1,15 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. - +use crate::global_state::GlobalState; use crate::js; use crate::ops; -use crate::state::CliState; +use crate::permissions::Permissions; +use crate::state::CliModuleLoader; use crate::worker::Worker; use crate::worker::WorkerEvent; use crate::worker::WorkerHandle; use deno_core::error::AnyError; use deno_core::v8; +use deno_core::ModuleSpecifier; use futures::channel::mpsc; use futures::future::FutureExt; use futures::stream::StreamExt; @@ -15,7 +17,6 @@ use std::future::Future; use std::ops::Deref; use std::ops::DerefMut; use std::pin::Pin; -use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::sync::Arc; @@ -85,10 +86,22 @@ pub struct WebWorker { impl WebWorker { pub fn new( name: String, - state: &Rc<CliState>, + permissions: Permissions, + main_module: ModuleSpecifier, + global_state: Arc<GlobalState>, has_deno_namespace: bool, ) -> Self { - let mut worker = Worker::new(name, Some(js::deno_isolate_init()), &state); + let loader = CliModuleLoader::new_for_worker(); + let mut worker = Worker::new( + name, + Some(js::deno_isolate_init()), + permissions, + main_module, + global_state, + loader, + false, + false, + ); let terminated = Arc::new(AtomicBool::new(false)); let isolate_handle = worker.isolate.thread_safe_handle(); @@ -252,13 +265,20 @@ impl Future for WebWorker { #[cfg(test)] mod tests { use super::*; - use crate::state::CliState; use crate::tokio_util; use crate::worker::WorkerEvent; fn create_test_worker() -> WebWorker { - let state = CliState::mock("./hello.js"); - let mut worker = WebWorker::new("TEST".to_string(), &state, false); + let main_module = + ModuleSpecifier::resolve_url_or_path("./hello.js").unwrap(); + let global_state = GlobalState::mock(vec!["deno".to_string()], None); + let mut worker = WebWorker::new( + "TEST".to_string(), + Permissions::allow_all(), + main_module, + global_state, + false, + ); worker .execute("bootstrap.workerRuntime(\"TEST\", false)") .unwrap(); diff --git a/cli/worker.rs b/cli/worker.rs index f575caddc..f87cd5cf1 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -2,13 +2,16 @@ use crate::fmt_errors::JsError; use crate::global_state::GlobalState; -use crate::global_timer::GlobalTimer; use crate::inspector::DenoInspector; use crate::js; use crate::metrics::Metrics; use crate::ops; use crate::ops::io::get_stdio; -use crate::state::CliState; +use crate::ops::timers; +use crate::ops::worker_host::WorkerId; +use crate::ops::worker_host::WorkersTable; +use crate::permissions::Permissions; +use crate::state::CliModuleLoader; use deno_core::error::AnyError; use deno_core::url::Url; use deno_core::JsRuntime; @@ -98,23 +101,28 @@ pub struct Worker { pub name: String, pub isolate: JsRuntime, pub inspector: Option<Box<DenoInspector>>, - pub state: Rc<CliState>, pub waker: AtomicWaker, pub(crate) internal_channels: WorkerChannelsInternal, external_channels: WorkerHandle, + should_break_on_first_statement: bool, } impl Worker { + #[allow(clippy::too_many_arguments)] pub fn new( name: String, startup_snapshot: Option<Snapshot>, - state: &Rc<CliState>, + permissions: Permissions, + main_module: ModuleSpecifier, + global_state: Arc<GlobalState>, + state: Rc<CliModuleLoader>, + is_main: bool, + is_internal: bool, ) -> Self { - let global_state = state.global_state.clone(); let global_state_ = global_state.clone(); let mut isolate = JsRuntime::new(RuntimeOptions { - module_loader: Some(state.clone()), + module_loader: Some(state), startup_snapshot, js_error_create_fn: Some(Box::new(move |core_js_error| { JsError::create(core_js_error, &global_state_.ts_compiler) @@ -125,40 +133,51 @@ impl Worker { let op_state = isolate.op_state(); let mut op_state = op_state.borrow_mut(); op_state.get_error_class_fn = &crate::errors::get_error_class_name; - op_state.put(state.clone()); let ca_file = global_state.flags.ca_file.as_deref(); let client = crate::http_util::create_http_client(ca_file).unwrap(); op_state.put(client); - op_state.put(GlobalTimer::default()); + op_state.put(timers::GlobalTimer::default()); + op_state.put(timers::StartTime::now()); if let Some(seed) = global_state.flags.seed { op_state.put(StdRng::seed_from_u64(seed)); } op_state.put(Metrics::default()); + + op_state.put(WorkersTable::default()); + op_state.put(WorkerId::default()); + + op_state.put(permissions); + + op_state.put(main_module); + op_state.put(global_state.clone()); } let inspector = { - let global_state = &state.global_state; global_state .flags .inspect .or(global_state.flags.inspect_brk) - .filter(|_| !state.is_internal) + .filter(|_| !is_internal) .map(|inspector_host| DenoInspector::new(&mut isolate, inspector_host)) }; + let should_break_on_first_statement = inspector.is_some() + && is_main + && global_state.flags.inspect_brk.is_some(); + let (internal_channels, external_channels) = create_channels(); Self { name, isolate, inspector, - state: state.clone(), waker: AtomicWaker::new(), internal_channels, external_channels, + should_break_on_first_statement, } } @@ -218,10 +237,7 @@ impl Worker { } fn wait_for_inspector_session(&mut self) { - let should_break_on_first_statement = self.inspector.is_some() && { - self.state.is_main && self.state.global_state.flags.inspect_brk.is_some() - }; - if should_break_on_first_statement { + if self.should_break_on_first_statement { self .inspector .as_mut() @@ -278,9 +294,21 @@ impl MainWorker { fn new( name: String, startup_snapshot: Option<Snapshot>, - state: &Rc<CliState>, + permissions: Permissions, + main_module: ModuleSpecifier, + global_state: Arc<GlobalState>, ) -> Self { - let mut worker = Worker::new(name, startup_snapshot, state); + let loader = CliModuleLoader::new(global_state.maybe_import_map.clone()); + let mut worker = Worker::new( + name, + startup_snapshot, + permissions, + main_module, + global_state, + loader, + true, + false, + ); { ops::runtime::init(&mut worker); ops::runtime_compiler::init(&mut worker); @@ -317,17 +345,12 @@ impl MainWorker { global_state: &Arc<GlobalState>, main_module: ModuleSpecifier, ) -> Result<MainWorker, AnyError> { - let state = CliState::new( - &global_state, - None, - main_module, - global_state.maybe_import_map.clone(), - false, - )?; let mut worker = MainWorker::new( "main".to_string(), Some(js::deno_isolate_init()), - &state, + global_state.permissions.clone(), + main_module, + global_state.clone(), ); { let op_state = worker.op_state(); @@ -380,11 +403,15 @@ mod tests { let module_specifier = ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap(); let global_state = GlobalState::new(flags::Flags::default()).unwrap(); - let state = - CliState::new(&global_state, None, module_specifier.clone(), None, false) - .unwrap(); + let global_state_ = global_state.clone(); tokio_util::run_basic(async { - let mut worker = MainWorker::new("TEST".to_string(), None, &state); + let mut worker = MainWorker::new( + "TEST".to_string(), + None, + global_state.permissions.clone(), + module_specifier.clone(), + global_state_, + ); let result = worker.execute_module(&module_specifier).await; if let Err(err) = result { eprintln!("execute_mod err {:?}", err); @@ -394,7 +421,7 @@ mod tests { } }); // Check that we didn't start the compiler. - assert_eq!(state.global_state.compiler_starts.load(Ordering::SeqCst), 0); + assert_eq!(global_state.compiler_starts.load(Ordering::SeqCst), 0); } #[test] @@ -406,11 +433,15 @@ mod tests { let module_specifier = ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap(); let global_state = GlobalState::new(flags::Flags::default()).unwrap(); - let state = - CliState::new(&global_state, None, module_specifier.clone(), None, false) - .unwrap(); + let global_state_ = global_state.clone(); tokio_util::run_basic(async { - let mut worker = MainWorker::new("TEST".to_string(), None, &state); + let mut worker = MainWorker::new( + "TEST".to_string(), + None, + global_state_.permissions.clone(), + module_specifier.clone(), + global_state_, + ); let result = worker.execute_module(&module_specifier).await; if let Err(err) = result { eprintln!("execute_mod err {:?}", err); @@ -421,7 +452,7 @@ mod tests { }); // Check that we didn't start the compiler. - assert_eq!(state.global_state.compiler_starts.load(Ordering::SeqCst), 0); + assert_eq!(global_state.compiler_starts.load(Ordering::SeqCst), 0); } #[tokio::test] @@ -441,13 +472,12 @@ mod tests { ..flags::Flags::default() }; let global_state = GlobalState::new(flags).unwrap(); - let state = - CliState::new(&global_state, None, module_specifier.clone(), None, false) - .unwrap(); let mut worker = MainWorker::new( "TEST".to_string(), Some(js::deno_isolate_init()), - &state, + global_state.permissions.clone(), + module_specifier.clone(), + global_state.clone(), ); worker.execute("bootstrap.mainRuntime()").unwrap(); let result = worker.execute_module(&module_specifier).await; @@ -458,15 +488,19 @@ mod tests { panic!("Future got unexpected error: {:?}", e); } // Check that we've only invoked the compiler once. - assert_eq!(state.global_state.compiler_starts.load(Ordering::SeqCst), 1); + assert_eq!(global_state.compiler_starts.load(Ordering::SeqCst), 1); } fn create_test_worker() -> MainWorker { - let state = CliState::mock("./hello.js"); + let main_module = + ModuleSpecifier::resolve_url_or_path("./hello.js").unwrap(); + let global_state = GlobalState::mock(vec!["deno".to_string()], None); let mut worker = MainWorker::new( "TEST".to_string(), Some(js::deno_isolate_init()), - &state, + Permissions::allow_all(), + main_module, + global_state, ); worker.execute("bootstrap.mainRuntime()").unwrap(); worker diff --git a/core/modules.rs b/core/modules.rs index b35e691c5..414423be2 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -5,10 +5,12 @@ use rusty_v8 as v8; use crate::error::generic_error; use crate::error::AnyError; use crate::module_specifier::ModuleSpecifier; +use crate::OpState; use futures::future::FutureExt; use futures::stream::FuturesUnordered; use futures::stream::Stream; use futures::stream::TryStreamExt; +use std::cell::RefCell; use std::collections::HashMap; use std::collections::HashSet; use std::future::Future; @@ -74,6 +76,7 @@ pub trait ModuleLoader { /// dynamic imports altogether. fn load( &self, + op_state: Rc<RefCell<OpState>>, module_specifier: &ModuleSpecifier, maybe_referrer: Option<ModuleSpecifier>, is_dyn_import: bool, @@ -89,6 +92,7 @@ pub trait ModuleLoader { /// It's not required to implement this method. fn prepare_load( &self, + _op_state: Rc<RefCell<OpState>>, _load_id: ModuleLoadId, _module_specifier: &ModuleSpecifier, _maybe_referrer: Option<String>, @@ -114,6 +118,7 @@ impl ModuleLoader for NoopModuleLoader { fn load( &self, + _op_state: Rc<RefCell<OpState>>, _module_specifier: &ModuleSpecifier, _maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, @@ -140,6 +145,7 @@ pub enum LoadState { /// This future is used to implement parallel async module loading. pub struct RecursiveModuleLoad { + op_state: Rc<RefCell<OpState>>, kind: Kind, // TODO(bartlomieju): in future this value should // be randomized @@ -154,16 +160,18 @@ pub struct RecursiveModuleLoad { impl RecursiveModuleLoad { /// Starts a new parallel load of the given URL of the main module. pub fn main( + op_state: Rc<RefCell<OpState>>, specifier: &str, code: Option<String>, loader: Rc<dyn ModuleLoader>, ) -> Self { let kind = Kind::Main; let state = LoadState::ResolveMain(specifier.to_owned(), code); - Self::new(kind, state, loader) + Self::new(op_state, kind, state, loader) } pub fn dynamic_import( + op_state: Rc<RefCell<OpState>>, specifier: &str, referrer: &str, loader: Rc<dyn ModuleLoader>, @@ -171,17 +179,23 @@ impl RecursiveModuleLoad { let kind = Kind::DynamicImport; let state = LoadState::ResolveImport(specifier.to_owned(), referrer.to_owned()); - Self::new(kind, state, loader) + Self::new(op_state, kind, state, loader) } pub fn is_dynamic_import(&self) -> bool { self.kind != Kind::Main } - fn new(kind: Kind, state: LoadState, loader: Rc<dyn ModuleLoader>) -> Self { + fn new( + op_state: Rc<RefCell<OpState>>, + kind: Kind, + state: LoadState, + loader: Rc<dyn ModuleLoader>, + ) -> Self { Self { id: NEXT_LOAD_ID.fetch_add(1, Ordering::SeqCst), root_module_id: None, + op_state, kind, state, loader, @@ -212,6 +226,7 @@ impl RecursiveModuleLoad { let prepare_result = self .loader .prepare_load( + self.op_state.clone(), self.id, &module_specifier, maybe_referrer, @@ -248,7 +263,12 @@ impl RecursiveModuleLoad { } _ => self .loader - .load(&module_specifier, None, self.is_dynamic_import()) + .load( + self.op_state.clone(), + &module_specifier, + None, + self.is_dynamic_import(), + ) .boxed_local(), }; @@ -264,10 +284,12 @@ impl RecursiveModuleLoad { referrer: ModuleSpecifier, ) { if !self.is_pending.contains(&specifier) { - let fut = - self - .loader - .load(&specifier, Some(referrer), self.is_dynamic_import()); + let fut = self.loader.load( + self.op_state.clone(), + &specifier, + Some(referrer), + self.is_dynamic_import(), + ); self.pending.push(fut.boxed_local()); self.is_pending.insert(specifier); } @@ -577,6 +599,7 @@ mod tests { fn load( &self, + _op_state: Rc<RefCell<OpState>>, module_specifier: &ModuleSpecifier, _maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, diff --git a/core/runtime.rs b/core/runtime.rs index e0a840c1a..9c076efd1 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -624,6 +624,7 @@ impl JsRuntimeState { debug!("dyn_import specifier {} referrer {} ", specifier, referrer); let load = RecursiveModuleLoad::dynamic_import( + self.op_state.clone(), specifier, referrer, self.loader.clone(), @@ -1207,7 +1208,12 @@ impl JsRuntime { state.loader.clone() }; - let load = RecursiveModuleLoad::main(&specifier.to_string(), code, loader); + let load = RecursiveModuleLoad::main( + self.op_state(), + &specifier.to_string(), + code, + loader, + ); let (_load_id, prepare_result) = load.prepare().await; let mut load = prepare_result?; @@ -1890,6 +1896,7 @@ pub mod tests { fn load( &self, + _op_state: Rc<RefCell<OpState>>, _module_specifier: &ModuleSpecifier, _maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, @@ -1999,6 +2006,7 @@ pub mod tests { fn load( &self, + _op_state: Rc<RefCell<OpState>>, _module_specifier: &ModuleSpecifier, _maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, @@ -2059,6 +2067,7 @@ pub mod tests { fn load( &self, + _op_state: Rc<RefCell<OpState>>, specifier: &ModuleSpecifier, _maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, @@ -2074,6 +2083,7 @@ pub mod tests { fn prepare_load( &self, + _op_state: Rc<RefCell<OpState>>, _load_id: ModuleLoadId, _module_specifier: &ModuleSpecifier, _maybe_referrer: Option<String>, @@ -2179,6 +2189,7 @@ pub mod tests { fn load( &self, + _op_state: Rc<RefCell<OpState>>, _module_specifier: &ModuleSpecifier, _maybe_referrer: Option<ModuleSpecifier>, _is_dyn_import: bool, diff --git a/op_crates/fetch/lib.rs b/op_crates/fetch/lib.rs index dbca63802..3692f916c 100644 --- a/op_crates/fetch/lib.rs +++ b/op_crates/fetch/lib.rs @@ -114,9 +114,7 @@ where { let state_ = state.borrow(); - // TODO(ry) The Rc below is a hack because we store Rc<CliState> in OpState. - // Ideally it could be removed. - let permissions = state_.borrow::<Rc<FP>>(); + let permissions = state_.borrow::<FP>(); permissions.check_net_url(&url_)?; } @@ -221,9 +219,7 @@ where let args: CreateHttpClientOptions = serde_json::from_value(args)?; if let Some(ca_file) = args.ca_file.clone() { - // TODO(ry) The Rc below is a hack because we store Rc<CliState> in OpState. - // Ideally it could be removed. - let permissions = state.borrow::<Rc<FP>>(); + let permissions = state.borrow::<FP>(); permissions.check_read(&PathBuf::from(ca_file))?; } |