1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

refactor: remove CliState, use OpState, add CliModuleLoader (#7588)

- remove "CliState.workers" and "CliState.next_worker_id", instead
store them on "OpState" using type aliases.
- remove "CliState.global_timer" and "CliState.start_time", instead
store them on "OpState" using type aliases.
- remove "CliState.is_internal", instead pass it to Worker::new
- move "CliState::permissions" to "OpState"
- move "CliState::main_module" to "OpState"
- move "CliState::global_state" to "OpState"
- move "CliState::check_unstable()" to "GlobalState"
- change "cli_state()" to "global_state()"
- change "deno_core::ModuleLoader" trait to pass "OpState" to callbacks
- rename "CliState" to "CliModuleLoader"
This commit is contained in:
Bartek Iwańczuk 2020-09-20 01:17:35 +02:00 committed by GitHub
parent aaa5e6613a
commit b657d743a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 551 additions and 519 deletions

View file

@ -10,7 +10,6 @@ use crate::media_type::MediaType;
use crate::module_graph::ModuleGraphFile; use crate::module_graph::ModuleGraphFile;
use crate::module_graph::ModuleGraphLoader; use crate::module_graph::ModuleGraphLoader;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::state::exit_unstable;
use crate::tsc::CompiledModule; use crate::tsc::CompiledModule;
use crate::tsc::TargetLib; use crate::tsc::TargetLib;
use crate::tsc::TsCompiler; use crate::tsc::TsCompiler;
@ -22,6 +21,14 @@ use std::sync::Arc;
use std::sync::Mutex; use std::sync::Mutex;
use tokio::sync::Mutex as AsyncMutex; 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. /// This structure represents state of single "deno" program.
/// ///
/// It is shared by all created workers (thus V8 isolates). /// It is shared by all created workers (thus V8 isolates).
@ -235,6 +242,16 @@ impl GlobalState {
Ok(compiled_module) 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)] #[cfg(test)]
pub fn mock( pub fn mock(
argv: Vec<String>, argv: Vec<String>,

View file

@ -1,47 +1 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // 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(()))
}
}

View file

@ -78,9 +78,9 @@ use flags::DenoSubcommand;
use flags::Flags; use flags::Flags;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::Future; use futures::Future;
use global_state::exit_unstable;
use log::Level; use log::Level;
use log::LevelFilter; use log::LevelFilter;
use state::exit_unstable;
use std::env; use std::env;
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;

View file

@ -37,7 +37,7 @@ fn op_apply_source_map(
args.line_number.into(), args.line_number.into(),
args.column_number.into(), args.column_number.into(),
&mut mappings_map, &mut mappings_map,
&super::cli_state(state).global_state.ts_compiler, &super::global_state(state).ts_compiler,
); );
Ok(json!({ Ok(json!({

View file

@ -1,12 +1,12 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // 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) { 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_async(rt, "op_fetch_read", deno_fetch::op_fetch_read);
super::reg_json_sync( super::reg_json_sync(
rt, rt,
"op_create_http_client", "op_create_http_client",
deno_fetch::op_create_http_client::<CliState>, deno_fetch::op_create_http_client::<Permissions>,
); );
} }

View file

@ -2,6 +2,7 @@
// Some deserializer fields are only used on Unix and Windows build fails without it // Some deserializer fields are only used on Unix and Windows build fails without it
use super::io::std_file_resource; use super::io::std_file_resource;
use super::io::{FileMetadata, StreamResource, StreamResourceHolder}; use super::io::{FileMetadata, StreamResource, StreamResourceHolder};
use crate::permissions::Permissions;
use deno_core::error::custom_error; use deno_core::error::custom_error;
use deno_core::error::type_error; use deno_core::error::type_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -151,15 +152,15 @@ fn open_helper(
let _ = mode; // avoid unused warning let _ = mode; // avoid unused warning
} }
let permissions = state.borrow::<Permissions>();
let options = args.options; let options = args.options;
if options.read { if options.read {
let cli_state = super::cli_state(state); permissions.check_read(&path)?;
cli_state.check_read(&path)?;
} }
if options.write || options.append { if options.write || options.append {
let cli_state = super::cli_state(state); permissions.check_write(&path)?;
cli_state.check_write(&path)?;
} }
open_options open_options
@ -280,7 +281,7 @@ fn op_fdatasync_sync(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
{ {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.fdatasync"); cli_state.check_unstable("Deno.fdatasync");
} }
let args: FdatasyncArgs = serde_json::from_value(args)?; let args: FdatasyncArgs = serde_json::from_value(args)?;
@ -297,7 +298,7 @@ async fn op_fdatasync_async(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> 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 args: FdatasyncArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
@ -320,7 +321,7 @@ fn op_fsync_sync(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
{ {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.fsync"); cli_state.check_unstable("Deno.fsync");
} }
let args: FsyncArgs = serde_json::from_value(args)?; let args: FsyncArgs = serde_json::from_value(args)?;
@ -337,7 +338,7 @@ async fn op_fsync_async(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> 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 args: FsyncArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
@ -360,7 +361,7 @@ fn op_fstat_sync(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
{ {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.fstat"); cli_state.check_unstable("Deno.fstat");
} }
let args: FstatArgs = serde_json::from_value(args)?; let args: FstatArgs = serde_json::from_value(args)?;
@ -377,7 +378,7 @@ async fn op_fstat_async(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> 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 args: FstatArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
@ -402,7 +403,7 @@ fn op_umask(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
{ {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.umask"); cli_state.check_unstable("Deno.umask");
} }
let args: UmaskArgs = serde_json::from_value(args)?; let args: UmaskArgs = serde_json::from_value(args)?;
@ -444,8 +445,7 @@ fn op_chdir(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: ChdirArgs = serde_json::from_value(args)?; let args: ChdirArgs = serde_json::from_value(args)?;
let d = PathBuf::from(&args.directory); let d = PathBuf::from(&args.directory);
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_read(&d)?;
cli_state.check_read(&d)?;
set_current_dir(&d)?; set_current_dir(&d)?;
Ok(json!({})) Ok(json!({}))
} }
@ -466,8 +466,7 @@ fn op_mkdir_sync(
let args: MkdirArgs = serde_json::from_value(args)?; let args: MkdirArgs = serde_json::from_value(args)?;
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
let mode = args.mode.unwrap_or(0o777) & 0o777; let mode = args.mode.unwrap_or(0o777) & 0o777;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_write(&path)?;
cli_state.check_write(&path)?;
debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive);
let mut builder = std::fs::DirBuilder::new(); let mut builder = std::fs::DirBuilder::new();
builder.recursive(args.recursive); builder.recursive(args.recursive);
@ -489,7 +488,10 @@ async fn op_mkdir_async(
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
let mode = args.mode.unwrap_or(0o777) & 0o777; 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 || { tokio::task::spawn_blocking(move || {
debug!("op_mkdir {} {:o} {}", path.display(), mode, args.recursive); 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 path = Path::new(&args.path).to_path_buf();
let mode = args.mode & 0o777; let mode = args.mode & 0o777;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_write(&path)?;
cli_state.check_write(&path)?;
debug!("op_chmod_sync {} {:o}", path.display(), mode); debug!("op_chmod_sync {} {:o}", path.display(), mode);
#[cfg(unix)] #[cfg(unix)]
{ {
@ -551,7 +552,10 @@ async fn op_chmod_async(
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
let mode = args.mode & 0o777; 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 || { tokio::task::spawn_blocking(move || {
debug!("op_chmod_async {} {:o}", path.display(), mode); debug!("op_chmod_async {} {:o}", path.display(), mode);
@ -589,8 +593,7 @@ fn op_chown_sync(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: ChownArgs = serde_json::from_value(args)?; let args: ChownArgs = serde_json::from_value(args)?;
let path = Path::new(&args.path).to_path_buf(); let path = Path::new(&args.path).to_path_buf();
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_write(&path)?;
cli_state.check_write(&path)?;
debug!( debug!(
"op_chown_sync {} {:?} {:?}", "op_chown_sync {} {:?} {:?}",
path.display(), path.display(),
@ -620,7 +623,10 @@ async fn op_chown_async(
let args: ChownArgs = serde_json::from_value(args)?; let args: ChownArgs = serde_json::from_value(args)?;
let path = Path::new(&args.path).to_path_buf(); 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 || { tokio::task::spawn_blocking(move || {
debug!( debug!(
@ -661,8 +667,7 @@ fn op_remove_sync(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let recursive = args.recursive; let recursive = args.recursive;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_write(&path)?;
cli_state.check_write(&path)?;
#[cfg(not(unix))] #[cfg(not(unix))]
use std::os::windows::prelude::MetadataExt; use std::os::windows::prelude::MetadataExt;
@ -705,7 +710,10 @@ async fn op_remove_async(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let recursive = args.recursive; 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 || { tokio::task::spawn_blocking(move || {
#[cfg(not(unix))] #[cfg(not(unix))]
@ -759,9 +767,9 @@ fn op_copy_file_sync(
let from = PathBuf::from(&args.from); let from = PathBuf::from(&args.from);
let to = PathBuf::from(&args.to); let to = PathBuf::from(&args.to);
let cli_state = super::cli_state(state); let permissions = state.borrow::<Permissions>();
cli_state.check_read(&from)?; permissions.check_read(&from)?;
cli_state.check_write(&to)?; permissions.check_write(&to)?;
debug!("op_copy_file_sync {} {}", from.display(), to.display()); debug!("op_copy_file_sync {} {}", from.display(), to.display());
// On *nix, Rust reports non-existent `from` as ErrorKind::InvalidInput // 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 from = PathBuf::from(&args.from);
let to = PathBuf::from(&args.to); let to = PathBuf::from(&args.to);
let cli_state = super::cli_state2(&state); {
cli_state.check_read(&from)?; let state = state.borrow();
cli_state.check_write(&to)?; let permissions = state.borrow::<Permissions>();
permissions.check_read(&from)?;
permissions.check_write(&to)?;
}
debug!("op_copy_file_async {} {}", from.display(), to.display()); debug!("op_copy_file_async {} {}", from.display(), to.display());
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -879,8 +890,7 @@ fn op_stat_sync(
let args: StatArgs = serde_json::from_value(args)?; let args: StatArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let lstat = args.lstat; let lstat = args.lstat;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_read(&path)?;
cli_state.check_read(&path)?;
debug!("op_stat_sync {} {}", path.display(), lstat); debug!("op_stat_sync {} {}", path.display(), lstat);
let metadata = if lstat { let metadata = if lstat {
std::fs::symlink_metadata(&path)? std::fs::symlink_metadata(&path)?
@ -899,7 +909,10 @@ async fn op_stat_async(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let lstat = args.lstat; 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 || { tokio::task::spawn_blocking(move || {
debug!("op_stat_async {} {}", path.display(), lstat); debug!("op_stat_async {} {}", path.display(), lstat);
@ -928,10 +941,10 @@ fn op_realpath_sync(
let args: RealpathArgs = serde_json::from_value(args)?; let args: RealpathArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let cli_state = super::cli_state(state); let permissions = state.borrow::<Permissions>();
cli_state.check_read(&path)?; permissions.check_read(&path)?;
if path.is_relative() { if path.is_relative() {
cli_state.check_read_blind(&current_dir()?, "CWD")?; permissions.check_read_blind(&current_dir()?, "CWD")?;
} }
debug!("op_realpath_sync {}", path.display()); debug!("op_realpath_sync {}", path.display());
@ -954,10 +967,13 @@ async fn op_realpath_async(
let args: RealpathArgs = serde_json::from_value(args)?; let args: RealpathArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let cli_state = super::cli_state2(&state); {
cli_state.check_read(&path)?; let state = state.borrow();
if path.is_relative() { let permissions = state.borrow::<Permissions>();
cli_state.check_read_blind(&current_dir()?, "CWD")?; permissions.check_read(&path)?;
if path.is_relative() {
permissions.check_read_blind(&current_dir()?, "CWD")?;
}
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
@ -990,8 +1006,7 @@ fn op_read_dir_sync(
let args: ReadDirArgs = serde_json::from_value(args)?; let args: ReadDirArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_read(&path)?;
cli_state.check_read(&path)?;
debug!("op_read_dir_sync {}", path.display()); debug!("op_read_dir_sync {}", path.display());
let entries: Vec<_> = std::fs::read_dir(path)? let entries: Vec<_> = std::fs::read_dir(path)?
@ -1022,7 +1037,10 @@ async fn op_read_dir_async(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: ReadDirArgs = serde_json::from_value(args)?; let args: ReadDirArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); 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 || { tokio::task::spawn_blocking(move || {
debug!("op_read_dir_async {}", path.display()); debug!("op_read_dir_async {}", path.display());
let entries: Vec<_> = std::fs::read_dir(path)? let entries: Vec<_> = std::fs::read_dir(path)?
@ -1065,10 +1083,10 @@ fn op_rename_sync(
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
let cli_state = super::cli_state(state); let permissions = state.borrow::<Permissions>();
cli_state.check_read(&oldpath)?; permissions.check_read(&oldpath)?;
cli_state.check_write(&oldpath)?; permissions.check_write(&oldpath)?;
cli_state.check_write(&newpath)?; permissions.check_write(&newpath)?;
debug!("op_rename_sync {} {}", oldpath.display(), newpath.display()); debug!("op_rename_sync {} {}", oldpath.display(), newpath.display());
std::fs::rename(&oldpath, &newpath)?; std::fs::rename(&oldpath, &newpath)?;
Ok(json!({})) Ok(json!({}))
@ -1083,10 +1101,11 @@ async fn op_rename_async(
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
{ {
let cli_state = super::cli_state2(&state); let state = state.borrow();
cli_state.check_read(&oldpath)?; let permissions = state.borrow::<Permissions>();
cli_state.check_write(&oldpath)?; permissions.check_read(&oldpath)?;
cli_state.check_write(&newpath)?; permissions.check_write(&oldpath)?;
permissions.check_write(&newpath)?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
debug!( debug!(
@ -1113,14 +1132,15 @@ fn op_link_sync(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.link"); cli_state.check_unstable("Deno.link");
let args: LinkArgs = serde_json::from_value(args)?; let args: LinkArgs = serde_json::from_value(args)?;
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
cli_state.check_read(&oldpath)?; let permissions = state.borrow::<Permissions>();
cli_state.check_write(&newpath)?; permissions.check_read(&oldpath)?;
permissions.check_write(&newpath)?;
debug!("op_link_sync {} {}", oldpath.display(), newpath.display()); debug!("op_link_sync {} {}", oldpath.display(), newpath.display());
std::fs::hard_link(&oldpath, &newpath)?; std::fs::hard_link(&oldpath, &newpath)?;
@ -1132,15 +1152,19 @@ async fn op_link_async(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state2(&state); let cli_state = super::global_state2(&state);
cli_state.check_unstable("Deno.link"); cli_state.check_unstable("Deno.link");
let args: LinkArgs = serde_json::from_value(args)?; let args: LinkArgs = serde_json::from_value(args)?;
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); 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 || { tokio::task::spawn_blocking(move || {
debug!("op_link_async {} {}", oldpath.display(), newpath.display()); debug!("op_link_async {} {}", oldpath.display(), newpath.display());
@ -1172,13 +1196,13 @@ fn op_symlink_sync(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.symlink"); cli_state.check_unstable("Deno.symlink");
let args: SymlinkArgs = serde_json::from_value(args)?; let args: SymlinkArgs = serde_json::from_value(args)?;
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); let newpath = PathBuf::from(&args.newpath);
cli_state.check_write(&newpath)?; state.borrow::<Permissions>().check_write(&newpath)?;
debug!( debug!(
"op_symlink_sync {} {}", "op_symlink_sync {} {}",
@ -1224,14 +1248,17 @@ async fn op_symlink_async(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state2(&state); let cli_state = super::global_state2(&state);
cli_state.check_unstable("Deno.symlink"); cli_state.check_unstable("Deno.symlink");
let args: SymlinkArgs = serde_json::from_value(args)?; let args: SymlinkArgs = serde_json::from_value(args)?;
let oldpath = PathBuf::from(&args.oldpath); let oldpath = PathBuf::from(&args.oldpath);
let newpath = PathBuf::from(&args.newpath); 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 || { tokio::task::spawn_blocking(move || {
debug!("op_symlink_async {} {}", oldpath.display(), newpath.display()); 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 args: ReadLinkArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_read(&path)?;
cli_state.check_read(&path)?;
debug!("op_read_link_value {}", path.display()); debug!("op_read_link_value {}", path.display());
let target = std::fs::read_link(&path)?.into_os_string(); let target = std::fs::read_link(&path)?.into_os_string();
@ -1302,7 +1328,10 @@ async fn op_read_link_async(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: ReadLinkArgs = serde_json::from_value(args)?; let args: ReadLinkArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); 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 || { tokio::task::spawn_blocking(move || {
debug!("op_read_link_async {}", path.display()); debug!("op_read_link_async {}", path.display());
let target = std::fs::read_link(&path)?.into_os_string(); let target = std::fs::read_link(&path)?.into_os_string();
@ -1326,7 +1355,7 @@ fn op_ftruncate_sync(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
{ {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.ftruncate"); cli_state.check_unstable("Deno.ftruncate");
} }
let args: FtruncateArgs = serde_json::from_value(args)?; let args: FtruncateArgs = serde_json::from_value(args)?;
@ -1344,7 +1373,7 @@ async fn op_ftruncate_async(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> 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 args: FtruncateArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
let len = args.len as u64; let len = args.len as u64;
@ -1371,8 +1400,7 @@ fn op_truncate_sync(
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let len = args.len; let len = args.len;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_write(&path)?;
cli_state.check_write(&path)?;
debug!("op_truncate_sync {} {}", path.display(), len); debug!("op_truncate_sync {} {}", path.display(), len);
let f = std::fs::OpenOptions::new().write(true).open(&path)?; 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 args: TruncateArgs = serde_json::from_value(args)?;
let path = PathBuf::from(&args.path); let path = PathBuf::from(&args.path);
let len = args.len; 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 || { tokio::task::spawn_blocking(move || {
debug!("op_truncate_async {} {}", path.display(), len); debug!("op_truncate_async {} {}", path.display(), len);
let f = std::fs::OpenOptions::new().write(true).open(&path)?; 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 prefix = args.prefix.map(String::from);
let suffix = args.suffix.map(String::from); let suffix = args.suffix.map(String::from);
let cli_state = super::cli_state(state); state
cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; .borrow::<Permissions>()
.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
// TODO(piscisaureus): use byte vector for paths, not a string. // TODO(piscisaureus): use byte vector for paths, not a string.
// See https://github.com/denoland/deno/issues/627. // 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 prefix = args.prefix.map(String::from);
let suffix = args.suffix.map(String::from); let suffix = args.suffix.map(String::from);
{ {
let cli_state = super::cli_state2(&state); let state = state.borrow();
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 || { tokio::task::spawn_blocking(move || {
// TODO(piscisaureus): use byte vector for paths, not a string. // 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 prefix = args.prefix.map(String::from);
let suffix = args.suffix.map(String::from); let suffix = args.suffix.map(String::from);
let cli_state = super::cli_state(state); state
cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; .borrow::<Permissions>()
.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
// TODO(piscisaureus): use byte vector for paths, not a string. // TODO(piscisaureus): use byte vector for paths, not a string.
// See https://github.com/denoland/deno/issues/627. // 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 suffix = args.suffix.map(String::from);
{ {
let state = state.borrow(); let state = state.borrow();
let cli_state = super::cli_state(&state); state
cli_state.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?; .borrow::<Permissions>()
.check_write(dir.clone().unwrap_or_else(temp_dir).as_path())?;
} }
tokio::task::spawn_blocking(move || { tokio::task::spawn_blocking(move || {
// TODO(piscisaureus): use byte vector for paths, not a string. // TODO(piscisaureus): use byte vector for paths, not a string.
@ -1591,7 +1627,7 @@ fn op_futime_sync(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
{ {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.futimeSync"); cli_state.check_unstable("Deno.futimeSync");
} }
let args: FutimeArgs = serde_json::from_value(args)?; let args: FutimeArgs = serde_json::from_value(args)?;
@ -1618,7 +1654,7 @@ async fn op_futime_async(
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let mut state = state.borrow_mut(); 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"); cli_state.check_unstable("Deno.futime");
let args: FutimeArgs = serde_json::from_value(args)?; let args: FutimeArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
@ -1651,7 +1687,7 @@ fn op_utime_sync(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
cli_state.check_unstable("Deno.utime"); cli_state.check_unstable("Deno.utime");
let args: UtimeArgs = serde_json::from_value(args)?; 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 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); 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)?; filetime::set_file_times(path, atime, mtime)?;
Ok(json!({})) Ok(json!({}))
} }
@ -1670,7 +1706,7 @@ async fn op_utime_async(
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let state = state.borrow(); let state = state.borrow();
let cli_state = super::cli_state(&state); let cli_state = super::global_state(&state);
cli_state.check_unstable("Deno.utime"); cli_state.check_unstable("Deno.utime");
let args: UtimeArgs = serde_json::from_value(args)?; 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 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); 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 || { tokio::task::spawn_blocking(move || {
filetime::set_file_times(path, atime, mtime)?; filetime::set_file_times(path, atime, mtime)?;
@ -1694,8 +1730,9 @@ fn op_cwd(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let path = current_dir()?; let path = current_dir()?;
let cli_state = super::cli_state(state); state
cli_state.check_read_blind(&path, "CWD")?; .borrow::<Permissions>()
.check_read_blind(&path, "CWD")?;
let path_str = into_string(path.into_os_string())?; let path_str = into_string(path.into_os_string())?;
Ok(json!(path_str)) Ok(json!(path_str))
} }

View file

@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // 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::bad_resource_id;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::BufVec; use deno_core::BufVec;
@ -91,7 +92,9 @@ fn op_fs_events_open(
RecursiveMode::NonRecursive RecursiveMode::NonRecursive
}; };
for path in &args.paths { 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)?; watcher.watch(path, recursive_mode)?;
} }
let resource = FsEventsResource { watcher, receiver }; let resource = FsEventsResource { watcher, receiver };

View file

@ -28,6 +28,7 @@ pub mod web_worker;
pub mod websocket; pub mod websocket;
pub mod worker_host; pub mod worker_host;
use crate::global_state::GlobalState;
use crate::metrics::metrics_op; use crate::metrics::metrics_op;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::json_op_async; use deno_core::json_op_async;
@ -40,6 +41,7 @@ use serde_json::Value;
use std::cell::RefCell; use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
pub fn reg_json_async<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F) pub fn reg_json_async<F, R>(rt: &mut JsRuntime, name: &'static str, op_fn: F)
where where
@ -58,12 +60,12 @@ where
} }
/// Helper for extracting the commonly used state. Used for sync ops. /// Helper for extracting the commonly used state. Used for sync ops.
pub fn cli_state(state: &OpState) -> Rc<crate::state::CliState> { pub fn global_state(state: &OpState) -> Arc<GlobalState> {
state.borrow::<Rc<crate::state::CliState>>().clone() state.borrow::<Arc<GlobalState>>().clone()
} }
/// Helper for extracting the commonly used state. Used for async ops. /// 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(); let state = state.borrow();
state.borrow::<Rc<crate::state::CliState>>().clone() state.borrow::<Arc<GlobalState>>().clone()
} }

View file

@ -2,6 +2,7 @@
use crate::ops::io::StreamResource; use crate::ops::io::StreamResource;
use crate::ops::io::StreamResourceHolder; use crate::ops::io::StreamResourceHolder;
use crate::permissions::Permissions;
use crate::resolve_addr::resolve_addr; use crate::resolve_addr::resolve_addr;
use deno_core::error::bad_resource; use deno_core::error::bad_resource;
use deno_core::error::bad_resource_id; use deno_core::error::bad_resource_id;
@ -189,7 +190,6 @@ async fn op_datagram_send(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
assert_eq!(zero_copy.len(), 1, "Invalid number of arguments"); assert_eq!(zero_copy.len(), 1, "Invalid number of arguments");
let zero_copy = zero_copy[0].clone(); let zero_copy = zero_copy[0].clone();
let cli_state = super::cli_state2(&state);
match serde_json::from_value(args)? { match serde_json::from_value(args)? {
SendArgs { SendArgs {
@ -197,7 +197,11 @@ async fn op_datagram_send(
transport, transport,
transport_args: ArgsEnum::Ip(args), transport_args: ArgsEnum::Ip(args),
} if transport == "udp" => { } 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)?; let addr = resolve_addr(&args.hostname, args.port)?;
poll_fn(move |cx| { poll_fn(move |cx| {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
@ -220,7 +224,10 @@ async fn op_datagram_send(
transport_args: ArgsEnum::Unix(args), transport_args: ArgsEnum::Unix(args),
} if transport == "unixpacket" => { } if transport == "unixpacket" => {
let address_path = Path::new(&args.path); 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 mut state = state.borrow_mut();
let resource = state let resource = state
.resource_table .resource_table
@ -251,13 +258,17 @@ async fn op_connect(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state2(&state);
match serde_json::from_value(args)? { match serde_json::from_value(args)? {
ConnectArgs { ConnectArgs {
transport, transport,
transport_args: ArgsEnum::Ip(args), transport_args: ArgsEnum::Ip(args),
} if transport == "tcp" => { } 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 addr = resolve_addr(&args.hostname, args.port)?;
let tcp_stream = TcpStream::connect(&addr).await?; let tcp_stream = TcpStream::connect(&addr).await?;
let local_addr = tcp_stream.local_addr()?; let local_addr = tcp_stream.local_addr()?;
@ -290,8 +301,12 @@ async fn op_connect(
transport_args: ArgsEnum::Unix(args), transport_args: ArgsEnum::Unix(args),
} if transport == "unix" => { } if transport == "unix" => {
let address_path = Path::new(&args.path); let address_path = Path::new(&args.path);
let cli_state = super::global_state2(&state);
cli_state.check_unstable("Deno.connect"); 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 path = args.path;
let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?; let unix_stream = net_unix::UnixStream::connect(Path::new(&path)).await?;
let local_addr = unix_stream.local_addr()?; let local_addr = unix_stream.local_addr()?;
@ -331,7 +346,7 @@ fn op_shutdown(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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)?; let args: ShutdownArgs = serde_json::from_value(args)?;
@ -475,7 +490,8 @@ fn op_listen(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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)? { match serde_json::from_value(args)? {
ListenArgs { ListenArgs {
transport, transport,
@ -485,7 +501,7 @@ fn op_listen(
if transport == "udp" { if transport == "udp" {
cli_state.check_unstable("Deno.listenDatagram"); 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 addr = resolve_addr(&args.hostname, args.port)?;
let (rid, local_addr) = if transport == "tcp" { let (rid, local_addr) = if transport == "tcp" {
@ -521,8 +537,8 @@ fn op_listen(
if transport == "unixpacket" { if transport == "unixpacket" {
cli_state.check_unstable("Deno.listenDatagram"); cli_state.check_unstable("Deno.listenDatagram");
} }
cli_state.check_read(&address_path)?; permissions.check_read(&address_path)?;
cli_state.check_write(&address_path)?; permissions.check_write(&address_path)?;
} }
let (rid, local_addr) = if transport == "unix" { let (rid, local_addr) = if transport == "unix" {
net_unix::listen_unix(state, &address_path)? net_unix::listen_unix(state, &address_path)?

View file

@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::permissions::Permissions;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::OpState; use deno_core::OpState;
@ -28,8 +29,9 @@ fn op_exec_path(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let current_exe = env::current_exe().unwrap(); let current_exe = env::current_exe().unwrap();
let cli_state = super::cli_state(state); state
cli_state.check_read_blind(&current_exe, "exec_path")?; .borrow::<Permissions>()
.check_read_blind(&current_exe, "exec_path")?;
// Now apply URL parser to current exe to get fully resolved path, otherwise // Now apply URL parser to current exe to get fully resolved path, otherwise
// we might get `./` and `../` bits in `exec_path` // we might get `./` and `../` bits in `exec_path`
let exe_url = Url::from_file_path(current_exe).unwrap(); let exe_url = Url::from_file_path(current_exe).unwrap();
@ -49,8 +51,7 @@ fn op_set_env(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: SetEnv = serde_json::from_value(args)?; let args: SetEnv = serde_json::from_value(args)?;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_env()?;
cli_state.check_env()?;
env::set_var(args.key, args.value); env::set_var(args.key, args.value);
Ok(json!({})) Ok(json!({}))
} }
@ -60,8 +61,7 @@ fn op_env(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_env()?;
cli_state.check_env()?;
let v = env::vars().collect::<HashMap<String, String>>(); let v = env::vars().collect::<HashMap<String, String>>();
Ok(json!(v)) Ok(json!(v))
} }
@ -77,8 +77,7 @@ fn op_get_env(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: GetEnv = serde_json::from_value(args)?; let args: GetEnv = serde_json::from_value(args)?;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_env()?;
cli_state.check_env()?;
let r = match env::var(args.key) { let r = match env::var(args.key) {
Err(env::VarError::NotPresent) => json!([]), Err(env::VarError::NotPresent) => json!([]),
v => json!([v?]), v => json!([v?]),
@ -97,8 +96,7 @@ fn op_delete_env(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: DeleteEnv = serde_json::from_value(args)?; let args: DeleteEnv = serde_json::from_value(args)?;
let cli_state = super::cli_state(state); state.borrow::<Permissions>().check_env()?;
cli_state.check_env()?;
env::remove_var(args.key); env::remove_var(args.key);
Ok(json!({})) Ok(json!({}))
} }
@ -122,9 +120,9 @@ fn op_loadavg(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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_unstable("Deno.loadavg");
cli_state.check_env()?; state.borrow::<Permissions>().check_env()?;
match sys_info::loadavg() { match sys_info::loadavg() {
Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])), Ok(loadavg) => Ok(json!([loadavg.one, loadavg.five, loadavg.fifteen])),
Err(_) => Ok(json!([0f64, 0f64, 0f64])), Err(_) => Ok(json!([0f64, 0f64, 0f64])),
@ -136,9 +134,9 @@ fn op_hostname(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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_unstable("Deno.hostname");
cli_state.check_env()?; state.borrow::<Permissions>().check_env()?;
let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string()); let hostname = sys_info::hostname().unwrap_or_else(|_| "".to_string());
Ok(json!(hostname)) Ok(json!(hostname))
} }
@ -148,9 +146,9 @@ fn op_os_release(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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_unstable("Deno.osRelease");
cli_state.check_env()?; state.borrow::<Permissions>().check_env()?;
let release = sys_info::os_release().unwrap_or_else(|_| "".to_string()); let release = sys_info::os_release().unwrap_or_else(|_| "".to_string());
Ok(json!(release)) Ok(json!(release))
} }
@ -160,9 +158,9 @@ fn op_system_memory_info(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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_unstable("Deno.systemMemoryInfo");
cli_state.check_env()?; state.borrow::<Permissions>().check_env()?;
match sys_info::mem_info() { match sys_info::mem_info() {
Ok(info) => Ok(json!({ Ok(info) => Ok(json!({
"total": info.total, "total": info.total,

View file

@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // 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::custom_error;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::OpState; use deno_core::OpState;
@ -27,8 +28,7 @@ pub fn op_query_permission(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: PermissionArgs = serde_json::from_value(args)?; let args: PermissionArgs = serde_json::from_value(args)?;
let cli_state = super::cli_state(state); let permissions = state.borrow::<Permissions>();
let permissions = cli_state.permissions.borrow();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.query_read(&path.as_deref().map(Path::new)), "read" => permissions.query_read(&path.as_deref().map(Path::new)),
@ -54,8 +54,7 @@ pub fn op_revoke_permission(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: PermissionArgs = serde_json::from_value(args)?; let args: PermissionArgs = serde_json::from_value(args)?;
let cli_state = super::cli_state(state); let permissions = state.borrow_mut::<Permissions>();
let mut permissions = cli_state.permissions.borrow_mut();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.revoke_read(&path.as_deref().map(Path::new)), "read" => permissions.revoke_read(&path.as_deref().map(Path::new)),
@ -81,8 +80,7 @@ pub fn op_request_permission(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: PermissionArgs = serde_json::from_value(args)?; let args: PermissionArgs = serde_json::from_value(args)?;
let cli_state = super::cli_state(state); let permissions = state.borrow_mut::<Permissions>();
let permissions = &mut cli_state.permissions.borrow_mut();
let path = args.path.as_deref(); let path = args.path.as_deref();
let perm = match args.name.as_ref() { let perm = match args.name.as_ref() {
"read" => permissions.request_read(&path.as_deref().map(Path::new)), "read" => permissions.request_read(&path.as_deref().map(Path::new)),

View file

@ -1,6 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::metrics::metrics_op; use crate::metrics::metrics_op;
use crate::permissions::Permissions;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::plugin_api; use deno_core::plugin_api;
use deno_core::BufVec; use deno_core::BufVec;
@ -39,9 +40,10 @@ pub fn op_open_plugin(
let args: OpenPluginArgs = serde_json::from_value(args)?; let args: OpenPluginArgs = serde_json::from_value(args)?;
let filename = PathBuf::from(&args.filename); 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_unstable("Deno.openPlugin");
cli_state.check_plugin(&filename)?; let permissions = state.borrow::<Permissions>();
permissions.check_plugin(&filename)?;
debug!("Loading Plugin: {:#?}", filename); debug!("Loading Plugin: {:#?}", filename);
let plugin_lib = Library::open(filename).map(Rc::new)?; let plugin_lib = Library::open(filename).map(Rc::new)?;

View file

@ -1,6 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use super::io::{std_file_resource, StreamResource, StreamResourceHolder}; use super::io::{std_file_resource, StreamResource, StreamResourceHolder};
use crate::permissions::Permissions;
use crate::signal::kill; use crate::signal::kill;
use deno_core::error::bad_resource_id; use deno_core::error::bad_resource_id;
use deno_core::error::type_error; use deno_core::error::type_error;
@ -68,7 +69,7 @@ fn op_run(
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let run_args: RunArgs = serde_json::from_value(args)?; 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 args = run_args.cmd;
let env = run_args.env; let env = run_args.env;
@ -178,7 +179,10 @@ async fn op_run_status(
let args: RunStatusArgs = serde_json::from_value(args)?; let args: RunStatusArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; 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 run_status = poll_fn(|cx| {
let mut state = state.borrow_mut(); let mut state = state.borrow_mut();
@ -221,9 +225,9 @@ fn op_kill(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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_unstable("Deno.kill");
cli_state.check_run()?; state.borrow::<Permissions>().check_run()?;
let args: KillArgs = serde_json::from_value(args)?; let args: KillArgs = serde_json::from_value(args)?;
kill(args.pid, args.signo)?; kill(args.pid, args.signo)?;

View file

@ -35,8 +35,8 @@ fn op_repl_start(
let args: ReplStartArgs = serde_json::from_value(args)?; let args: ReplStartArgs = serde_json::from_value(args)?;
debug!("op_repl_start {}", args.history_file); debug!("op_repl_start {}", args.history_file);
let history_path = { let history_path = {
let cli_state = super::cli_state(state); let cli_state = super::global_state(state);
repl::history_path(&cli_state.global_state.dir, &args.history_file) repl::history_path(&cli_state.dir, &args.history_file)
}; };
let repl = repl::Repl::new(history_path); let repl = repl::Repl::new(history_path);
let resource = ReplResource(Arc::new(Mutex::new(repl))); let resource = ReplResource(Arc::new(Mutex::new(repl)));

View file

@ -2,6 +2,7 @@
use crate::colors; use crate::colors;
use crate::metrics::Metrics; use crate::metrics::Metrics;
use crate::permissions::Permissions;
use crate::version; use crate::version;
use crate::DenoSubcommand; use crate::DenoSubcommand;
use deno_core::error::AnyError; use deno_core::error::AnyError;
@ -22,7 +23,7 @@ fn op_start(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let gs = &super::cli_state(state).global_state; let gs = &super::global_state(state);
Ok(json!({ Ok(json!({
// TODO(bartlomieju): `cwd` field is not used in JS, remove? // TODO(bartlomieju): `cwd` field is not used in JS, remove?
@ -47,12 +48,13 @@ fn op_main_module(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state); let main = state.borrow::<ModuleSpecifier>().to_string();
let main = &cli_state.main_module.to_string();
let main_url = ModuleSpecifier::resolve_url_or_path(&main)?; let main_url = ModuleSpecifier::resolve_url_or_path(&main)?;
if main_url.as_url().scheme() == "file" { if main_url.as_url().scheme() == "file" {
let main_path = std::env::current_dir().unwrap().join(main_url.to_string()); 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)) Ok(json!(&main))
} }

View file

@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::permissions::Permissions;
use crate::tsc::runtime_bundle; use crate::tsc::runtime_bundle;
use crate::tsc::runtime_compile; use crate::tsc::runtime_compile;
use crate::tsc::runtime_transpile; use crate::tsc::runtime_transpile;
@ -32,11 +33,14 @@ async fn op_compile(
args: Value, args: Value,
_data: BufVec, _data: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state2(&state); let cli_state = super::global_state2(&state);
cli_state.check_unstable("Deno.compile"); cli_state.check_unstable("Deno.compile");
let args: CompileArgs = serde_json::from_value(args)?; let args: CompileArgs = serde_json::from_value(args)?;
let global_state = cli_state.global_state.clone(); let global_state = cli_state.clone();
let permissions = cli_state.permissions.borrow().clone(); let permissions = {
let state = state.borrow();
state.borrow::<Permissions>().clone()
};
let fut = if args.bundle { let fut = if args.bundle {
runtime_bundle( runtime_bundle(
&global_state, &global_state,
@ -71,11 +75,14 @@ async fn op_transpile(
args: Value, args: Value,
_data: BufVec, _data: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state2(&state); let cli_state = super::global_state2(&state);
cli_state.check_unstable("Deno.transpile"); cli_state.check_unstable("Deno.transpile");
let args: TranspileArgs = serde_json::from_value(args)?; let args: TranspileArgs = serde_json::from_value(args)?;
let global_state = cli_state.global_state.clone(); let global_state = cli_state.clone();
let permissions = cli_state.permissions.borrow().clone(); let permissions = {
let state = state.borrow();
state.borrow::<Permissions>().clone()
};
let result = let result =
runtime_transpile(&global_state, permissions, &args.sources, &args.options) runtime_transpile(&global_state, permissions, &args.sources, &args.options)
.await?; .await?;

View file

@ -48,7 +48,7 @@ fn op_signal_bind(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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 args: BindSignalArgs = serde_json::from_value(args)?;
let rid = state.resource_table.add( let rid = state.resource_table.add(
"signal", "signal",
@ -68,7 +68,7 @@ async fn op_signal_poll(
args: Value, args: Value,
_zero_copy: BufVec, _zero_copy: BufVec,
) -> Result<Value, AnyError> { ) -> 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 args: SignalArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
@ -92,7 +92,7 @@ pub fn op_signal_unbind(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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 args: SignalArgs = serde_json::from_value(args)?;
let rid = args.rid as u32; let rid = args.rid as u32;
let resource = state.resource_table.get_mut::<SignalStreamResource>(rid); let resource = state.resource_table.get_mut::<SignalStreamResource>(rid);

View file

@ -1,17 +1,61 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // 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::error::AnyError;
use deno_core::BufVec; use deno_core::BufVec;
use deno_core::OpState; use deno_core::OpState;
use deno_core::ZeroCopyBuf; use deno_core::ZeroCopyBuf;
use futures::future::FutureExt; use futures::channel::oneshot;
use futures::FutureExt;
use futures::TryFutureExt;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell; use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc; use std::rc::Rc;
use std::time::Duration; use std::time::Duration;
use std::time::Instant; 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) { pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop); super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
@ -61,15 +105,15 @@ fn op_now(
_args: Value, _args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state); let start_time = state.borrow::<StartTime>();
let seconds = cli_state.start_time.elapsed().as_secs(); let seconds = start_time.elapsed().as_secs();
let mut subsec_nanos = cli_state.start_time.elapsed().subsec_nanos(); let mut subsec_nanos = start_time.elapsed().subsec_nanos();
let reduced_time_precision = 2_000_000; // 2ms in nanoseconds let reduced_time_precision = 2_000_000; // 2ms in nanoseconds
// If the permission is not enabled // If the permission is not enabled
// Round the nano result on 2 milliseconds // Round the nano result on 2 milliseconds
// see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision // 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; subsec_nanos -= subsec_nanos % reduced_time_precision;
} }

View file

@ -1,6 +1,7 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use super::io::{StreamResource, StreamResourceHolder}; use super::io::{StreamResource, StreamResourceHolder};
use crate::permissions::Permissions;
use crate::resolve_addr::resolve_addr; use crate::resolve_addr::resolve_addr;
use deno_core::error::bad_resource; use deno_core::error::bad_resource;
use deno_core::error::bad_resource_id; use deno_core::error::bad_resource_id;
@ -72,11 +73,13 @@ async fn op_start_tls(
domain.push_str("localhost"); 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_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() { if let Some(path) = cert_file.clone() {
cli_state.check_read(Path::new(&path))?; permissions.check_read(Path::new(&path))?;
} }
} }
let mut resource_holder = { let mut resource_holder = {
@ -143,10 +146,11 @@ async fn op_connect_tls(
let args: ConnectTLSArgs = serde_json::from_value(args)?; let args: ConnectTLSArgs = serde_json::from_value(args)?;
let cert_file = args.cert_file.clone(); let cert_file = args.cert_file.clone();
{ {
let cli_state = super::cli_state2(&state); let s = state.borrow();
cli_state.check_net(&args.hostname, args.port)?; let permissions = s.borrow::<Permissions>();
permissions.check_net(&args.hostname, args.port)?;
if let Some(path) = cert_file.clone() { 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(); let mut domain = args.hostname.clone();
@ -318,10 +322,10 @@ fn op_listen_tls(
let cert_file = args.cert_file; let cert_file = args.cert_file;
let key_file = args.key_file; let key_file = args.key_file;
{ {
let cli_state = super::cli_state(state); let permissions = state.borrow::<Permissions>();
cli_state.check_net(&args.hostname, args.port)?; permissions.check_net(&args.hostname, args.port)?;
cli_state.check_read(Path::new(&cert_file))?; permissions.check_read(Path::new(&cert_file))?;
cli_state.check_read(Path::new(&key_file))?; permissions.check_read(Path::new(&key_file))?;
} }
let mut config = ServerConfig::new(NoClientAuth::new()); let mut config = ServerConfig::new(NoClientAuth::new());
config config

View file

@ -62,7 +62,7 @@ fn op_set_raw(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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 args: SetRawArgs = serde_json::from_value(args)?;
let rid = args.rid; let rid = args.rid;
@ -273,7 +273,7 @@ fn op_console_size(
args: Value, args: Value,
_zero_copy: &mut [ZeroCopyBuf], _zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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 args: ConsoleSizeArgs = serde_json::from_value(args)?;
let rid = args.rid; let rid = args.rid;

View file

@ -1,5 +1,6 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::permissions::Permissions;
use core::task::Poll; use core::task::Poll;
use deno_core::error::bad_resource_id; use deno_core::error::bad_resource_id;
use deno_core::error::type_error; use deno_core::error::type_error;
@ -55,10 +56,14 @@ pub async fn op_ws_create(
_bufs: BufVec, _bufs: BufVec,
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: CreateArgs = serde_json::from_value(args)?; 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 ca_file = {
let cli_state = super::cli_state2(&state); let cli_state = super::global_state2(&state);
cli_state.check_net_url(&url::Url::parse(&args.url)?)?; cli_state.flags.ca_file.clone()
cli_state.global_state.flags.ca_file.clone()
}; };
let uri: Uri = args.url.parse()?; let uri: Uri = args.url.parse()?;
let request = Request::builder() let request = Request::builder()

View file

@ -17,6 +17,7 @@ use futures::future::FutureExt;
use serde::Deserialize; use serde::Deserialize;
use serde_json::Value; use serde_json::Value;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::From; use std::convert::From;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; 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); 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( fn create_web_worker(
worker_id: u32, worker_id: u32,
name: String, name: String,
@ -41,13 +45,13 @@ fn create_web_worker(
specifier: ModuleSpecifier, specifier: ModuleSpecifier,
has_deno_namespace: bool, has_deno_namespace: bool,
) -> Result<WebWorker, AnyError> { ) -> Result<WebWorker, AnyError> {
let cli_state = crate::state::CliState::new_for_worker( let mut worker = WebWorker::new(
global_state, name.clone(),
Some(permissions), permissions,
specifier, specifier,
)?; global_state.clone(),
has_deno_namespace,
let mut worker = WebWorker::new(name.clone(), &cli_state, has_deno_namespace); );
if has_deno_namespace { if has_deno_namespace {
let state = worker.isolate.op_state(); let state = worker.isolate.op_state();
@ -178,7 +182,7 @@ fn op_create_worker(
args: Value, args: Value,
_data: &mut [ZeroCopyBuf], _data: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> { ) -> 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 args: CreateWorkerArgs = serde_json::from_value(args)?;
let specifier = args.specifier.clone(); let specifier = args.specifier.clone();
@ -192,10 +196,9 @@ fn op_create_worker(
if use_deno_namespace { if use_deno_namespace {
cli_state.check_unstable("Worker.deno"); cli_state.check_unstable("Worker.deno");
} }
let global_state = cli_state.global_state.clone(); let permissions = state.borrow::<Permissions>().clone();
let permissions = cli_state.permissions.borrow().clone(); let worker_id = state.take::<WorkerId>();
let worker_id = cli_state.next_worker_id.get(); state.put::<WorkerId>(worker_id + 1);
cli_state.next_worker_id.set(worker_id + 1);
let module_specifier = ModuleSpecifier::resolve_url(&specifier)?; let module_specifier = ModuleSpecifier::resolve_url(&specifier)?;
let worker_name = args_name.unwrap_or_else(|| "".to_string()); 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( let (join_handle, worker_handle) = run_worker_thread(
worker_id, worker_id,
worker_name, worker_name,
&global_state, &cli_state,
permissions, permissions,
module_specifier, module_specifier,
use_deno_namespace, use_deno_namespace,
@ -211,10 +214,8 @@ fn op_create_worker(
)?; )?;
// At this point all interactions with worker happen using thread // At this point all interactions with worker happen using thread
// safe handler returned from previous function call // safe handler returned from previous function call
let cli_state = super::cli_state(state); state
cli_state .borrow_mut::<WorkersTable>()
.workers
.borrow_mut()
.insert(worker_id, (join_handle, worker_handle)); .insert(worker_id, (join_handle, worker_handle));
Ok(json!({ "id": worker_id })) Ok(json!({ "id": worker_id }))
@ -232,10 +233,8 @@ fn op_host_terminate_worker(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: WorkerArgs = serde_json::from_value(args)?; let args: WorkerArgs = serde_json::from_value(args)?;
let id = args.id as u32; let id = args.id as u32;
let cli_state = super::cli_state(state); let (join_handle, worker_handle) = state
let (join_handle, worker_handle) = cli_state .borrow_mut::<WorkersTable>()
.workers
.borrow_mut()
.remove(&id) .remove(&id)
.expect("No worker handle found"); .expect("No worker handle found");
worker_handle.terminate(); worker_handle.terminate();
@ -301,10 +300,10 @@ async fn op_host_get_message(
) -> Result<Value, AnyError> { ) -> Result<Value, AnyError> {
let args: WorkerArgs = serde_json::from_value(args)?; let args: WorkerArgs = serde_json::from_value(args)?;
let id = args.id as u32; let id = args.id as u32;
let cli_state = super::cli_state2(&state);
let worker_handle = { 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); let maybe_handle = workers_table.get(&id);
if let Some(handle) = maybe_handle { if let Some(handle) = maybe_handle {
handle.1.clone() handle.1.clone()
@ -318,8 +317,9 @@ async fn op_host_get_message(
Some(event) => { Some(event) => {
// Terminal error means that worker should be removed from worker table. // Terminal error means that worker should be removed from worker table.
if let WorkerEvent::TerminalError(_) = &event { if let WorkerEvent::TerminalError(_) = &event {
let mut s = state.borrow_mut();
if let Some((join_handle, mut worker_handle)) = 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(); worker_handle.sender.close_channel();
join_handle.join().expect("Worker thread panicked"); join_handle.join().expect("Worker thread panicked");
@ -329,7 +329,8 @@ async fn op_host_get_message(
} }
None => { None => {
// Worker shuts down // 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 // 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. // 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) { 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(); let msg = Vec::from(&*data[0]).into_boxed_slice();
debug!("post message to worker {}", id); debug!("post message to worker {}", id);
let cli_state = super::cli_state(state); let workers = state.borrow::<WorkersTable>();
let workers = cli_state.workers.borrow();
let worker_handle = workers[&id].1.clone(); let worker_handle = workers[&id].1.clone();
worker_handle.post_message(msg)?; worker_handle.post_message(msg)?;
Ok(json!({})) Ok(json!({}))

View file

@ -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. /// Shows the permission prompt and returns the answer according to the user input.
/// This loops until the user gives the proper input. /// This loops until the user gives the proper input.
#[cfg(not(test))] #[cfg(not(test))]

View file

@ -1,58 +1,49 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::file_fetcher::SourceFileFetcher;
use crate::global_state::GlobalState; use crate::global_state::GlobalState;
use crate::import_map::ImportMap; use crate::import_map::ImportMap;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::tsc::TargetLib; use crate::tsc::TargetLib;
use crate::web_worker::WebWorkerHandle;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::url;
use deno_core::ModuleLoadId; use deno_core::ModuleLoadId;
use deno_core::ModuleLoader; use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier; use deno_core::ModuleSpecifier;
use deno_core::OpState;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::Future; use futures::Future;
use std::cell::Cell;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::Rc;
use std::str; use std::str;
use std::sync::Arc; 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 pub struct CliModuleLoader {
// 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,
/// When flags contains a `.import_map_path` option, the content of the /// When flags contains a `.import_map_path` option, the content of the
/// import map file will be resolved and set. /// import map file will be resolved and set.
pub import_map: Option<ImportMap>, 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 target_lib: TargetLib,
pub is_main: bool, pub is_main: bool,
pub is_internal: bool,
} }
pub fn exit_unstable(api_name: &str) { impl CliModuleLoader {
eprintln!( pub fn new(maybe_import_map: Option<ImportMap>) -> Rc<Self> {
"Unstable API '{}'. The --unstable flag must be provided.", Rc::new(CliModuleLoader {
api_name import_map: maybe_import_map,
); target_lib: TargetLib::Main,
std::process::exit(70); 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( fn resolve(
&self, &self,
specifier: &str, specifier: &str,
@ -75,13 +66,17 @@ impl ModuleLoader for CliState {
fn load( fn load(
&self, &self,
op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier, module_specifier: &ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>, maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,
) -> Pin<Box<deno_core::ModuleSourceFuture>> { ) -> Pin<Box<deno_core::ModuleSourceFuture>> {
let module_specifier = module_specifier.to_owned(); let module_specifier = module_specifier.to_owned();
let module_url_specified = module_specifier.to_string(); 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 // TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param
let fut = async move { let fut = async move {
@ -102,6 +97,7 @@ impl ModuleLoader for CliState {
fn prepare_load( fn prepare_load(
&self, &self,
op_state: Rc<RefCell<OpState>>,
_load_id: ModuleLoadId, _load_id: ModuleLoadId,
module_specifier: &ModuleSpecifier, module_specifier: &ModuleSpecifier,
maybe_referrer: Option<String>, maybe_referrer: Option<String>,
@ -110,15 +106,19 @@ impl ModuleLoader for CliState {
let module_specifier = module_specifier.clone(); let module_specifier = module_specifier.clone();
let target_lib = self.target_lib.clone(); let target_lib = self.target_lib.clone();
let maybe_import_map = self.import_map.clone(); let maybe_import_map = self.import_map.clone();
let state = op_state.borrow();
// Only "main" module is loaded without permission check, // Only "main" module is loaded without permission check,
// ie. module that is associated with "is_main" state // ie. module that is associated with "is_main" state
// and is not a dynamic import. // and is not a dynamic import.
let permissions = if self.is_main && !is_dyn_import { let permissions = if self.is_main && !is_dyn_import {
Permissions::allow_all() Permissions::allow_all()
} else { } 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 // TODO(bartlomieju): I'm not sure if it's correct to ignore
// bad referrer - this is the case for `Deno.core.evalContext()` where // bad referrer - this is the case for `Deno.core.evalContext()` where
// `ref_str` is `<unknown>`. // `ref_str` is `<unknown>`.
@ -144,168 +144,3 @@ impl ModuleLoader for CliState {
.boxed_local() .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)
}
}

View file

@ -18,7 +18,7 @@ use crate::module_graph::ModuleGraphLoader;
use crate::ops; use crate::ops;
use crate::permissions::Permissions; use crate::permissions::Permissions;
use crate::source_maps::SourceMapGetter; use crate::source_maps::SourceMapGetter;
use crate::state::CliState; use crate::state::CliModuleLoader;
use crate::tsc_config; use crate::tsc_config;
use crate::version; use crate::version;
use crate::worker::Worker; use crate::worker::Worker;
@ -48,7 +48,6 @@ use std::ops::DerefMut;
use std::path::Path; use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc;
use std::str; use std::str;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
@ -132,9 +131,25 @@ pub struct CompilerWorker {
} }
impl CompilerWorker { impl CompilerWorker {
pub fn new(name: String, state: &Rc<CliState>) -> Self { pub fn new(
let mut worker = name: String,
Worker::new(name, Some(js::compiler_isolate_init()), state); 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)); let response = Arc::new(Mutex::new(None));
ops::runtime::init(&mut worker); ops::runtime::init(&mut worker);
ops::errors::init(&mut worker); ops::errors::init(&mut worker);
@ -215,17 +230,12 @@ fn create_compiler_worker(
global_state: &Arc<GlobalState>, global_state: &Arc<GlobalState>,
permissions: Permissions, permissions: Permissions,
) -> CompilerWorker { ) -> 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 // TODO(bartlomieju): this metric is never used anywhere
// Count how many times we start the compiler worker. // Count how many times we start the compiler worker.
global_state.compiler_starts.fetch_add(1, Ordering::SeqCst); 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 worker
.execute("globalThis.bootstrapCompilerRuntime()") .execute("globalThis.bootstrapCompilerRuntime()")
.unwrap(); .unwrap();

View file

@ -1,13 +1,15 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::global_state::GlobalState;
use crate::js; use crate::js;
use crate::ops; use crate::ops;
use crate::state::CliState; use crate::permissions::Permissions;
use crate::state::CliModuleLoader;
use crate::worker::Worker; use crate::worker::Worker;
use crate::worker::WorkerEvent; use crate::worker::WorkerEvent;
use crate::worker::WorkerHandle; use crate::worker::WorkerHandle;
use deno_core::error::AnyError; use deno_core::error::AnyError;
use deno_core::v8; use deno_core::v8;
use deno_core::ModuleSpecifier;
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::stream::StreamExt; use futures::stream::StreamExt;
@ -15,7 +17,6 @@ use std::future::Future;
use std::ops::Deref; use std::ops::Deref;
use std::ops::DerefMut; use std::ops::DerefMut;
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
@ -85,10 +86,22 @@ pub struct WebWorker {
impl WebWorker { impl WebWorker {
pub fn new( pub fn new(
name: String, name: String,
state: &Rc<CliState>, permissions: Permissions,
main_module: ModuleSpecifier,
global_state: Arc<GlobalState>,
has_deno_namespace: bool, has_deno_namespace: bool,
) -> Self { ) -> 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 terminated = Arc::new(AtomicBool::new(false));
let isolate_handle = worker.isolate.thread_safe_handle(); let isolate_handle = worker.isolate.thread_safe_handle();
@ -252,13 +265,20 @@ impl Future for WebWorker {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::state::CliState;
use crate::tokio_util; use crate::tokio_util;
use crate::worker::WorkerEvent; use crate::worker::WorkerEvent;
fn create_test_worker() -> WebWorker { fn create_test_worker() -> WebWorker {
let state = CliState::mock("./hello.js"); let main_module =
let mut worker = WebWorker::new("TEST".to_string(), &state, false); 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 worker
.execute("bootstrap.workerRuntime(\"TEST\", false)") .execute("bootstrap.workerRuntime(\"TEST\", false)")
.unwrap(); .unwrap();

View file

@ -2,13 +2,16 @@
use crate::fmt_errors::JsError; use crate::fmt_errors::JsError;
use crate::global_state::GlobalState; use crate::global_state::GlobalState;
use crate::global_timer::GlobalTimer;
use crate::inspector::DenoInspector; use crate::inspector::DenoInspector;
use crate::js; use crate::js;
use crate::metrics::Metrics; use crate::metrics::Metrics;
use crate::ops; use crate::ops;
use crate::ops::io::get_stdio; 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::error::AnyError;
use deno_core::url::Url; use deno_core::url::Url;
use deno_core::JsRuntime; use deno_core::JsRuntime;
@ -98,23 +101,28 @@ pub struct Worker {
pub name: String, pub name: String,
pub isolate: JsRuntime, pub isolate: JsRuntime,
pub inspector: Option<Box<DenoInspector>>, pub inspector: Option<Box<DenoInspector>>,
pub state: Rc<CliState>,
pub waker: AtomicWaker, pub waker: AtomicWaker,
pub(crate) internal_channels: WorkerChannelsInternal, pub(crate) internal_channels: WorkerChannelsInternal,
external_channels: WorkerHandle, external_channels: WorkerHandle,
should_break_on_first_statement: bool,
} }
impl Worker { impl Worker {
#[allow(clippy::too_many_arguments)]
pub fn new( pub fn new(
name: String, name: String,
startup_snapshot: Option<Snapshot>, 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 { ) -> Self {
let global_state = state.global_state.clone();
let global_state_ = global_state.clone(); let global_state_ = global_state.clone();
let mut isolate = JsRuntime::new(RuntimeOptions { let mut isolate = JsRuntime::new(RuntimeOptions {
module_loader: Some(state.clone()), module_loader: Some(state),
startup_snapshot, startup_snapshot,
js_error_create_fn: Some(Box::new(move |core_js_error| { js_error_create_fn: Some(Box::new(move |core_js_error| {
JsError::create(core_js_error, &global_state_.ts_compiler) JsError::create(core_js_error, &global_state_.ts_compiler)
@ -125,40 +133,51 @@ impl Worker {
let op_state = isolate.op_state(); let op_state = isolate.op_state();
let mut op_state = op_state.borrow_mut(); let mut op_state = op_state.borrow_mut();
op_state.get_error_class_fn = &crate::errors::get_error_class_name; 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 ca_file = global_state.flags.ca_file.as_deref();
let client = crate::http_util::create_http_client(ca_file).unwrap(); let client = crate::http_util::create_http_client(ca_file).unwrap();
op_state.put(client); 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 { if let Some(seed) = global_state.flags.seed {
op_state.put(StdRng::seed_from_u64(seed)); op_state.put(StdRng::seed_from_u64(seed));
} }
op_state.put(Metrics::default()); 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 inspector = {
let global_state = &state.global_state;
global_state global_state
.flags .flags
.inspect .inspect
.or(global_state.flags.inspect_brk) .or(global_state.flags.inspect_brk)
.filter(|_| !state.is_internal) .filter(|_| !is_internal)
.map(|inspector_host| DenoInspector::new(&mut isolate, inspector_host)) .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(); let (internal_channels, external_channels) = create_channels();
Self { Self {
name, name,
isolate, isolate,
inspector, inspector,
state: state.clone(),
waker: AtomicWaker::new(), waker: AtomicWaker::new(),
internal_channels, internal_channels,
external_channels, external_channels,
should_break_on_first_statement,
} }
} }
@ -218,10 +237,7 @@ impl Worker {
} }
fn wait_for_inspector_session(&mut self) { fn wait_for_inspector_session(&mut self) {
let should_break_on_first_statement = self.inspector.is_some() && { if self.should_break_on_first_statement {
self.state.is_main && self.state.global_state.flags.inspect_brk.is_some()
};
if should_break_on_first_statement {
self self
.inspector .inspector
.as_mut() .as_mut()
@ -278,9 +294,21 @@ impl MainWorker {
fn new( fn new(
name: String, name: String,
startup_snapshot: Option<Snapshot>, startup_snapshot: Option<Snapshot>,
state: &Rc<CliState>, permissions: Permissions,
main_module: ModuleSpecifier,
global_state: Arc<GlobalState>,
) -> Self { ) -> 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::init(&mut worker);
ops::runtime_compiler::init(&mut worker); ops::runtime_compiler::init(&mut worker);
@ -317,17 +345,12 @@ impl MainWorker {
global_state: &Arc<GlobalState>, global_state: &Arc<GlobalState>,
main_module: ModuleSpecifier, main_module: ModuleSpecifier,
) -> Result<MainWorker, AnyError> { ) -> Result<MainWorker, AnyError> {
let state = CliState::new(
&global_state,
None,
main_module,
global_state.maybe_import_map.clone(),
false,
)?;
let mut worker = MainWorker::new( let mut worker = MainWorker::new(
"main".to_string(), "main".to_string(),
Some(js::deno_isolate_init()), Some(js::deno_isolate_init()),
&state, global_state.permissions.clone(),
main_module,
global_state.clone(),
); );
{ {
let op_state = worker.op_state(); let op_state = worker.op_state();
@ -380,11 +403,15 @@ mod tests {
let module_specifier = let module_specifier =
ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap(); ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
let global_state = GlobalState::new(flags::Flags::default()).unwrap(); let global_state = GlobalState::new(flags::Flags::default()).unwrap();
let state = let global_state_ = global_state.clone();
CliState::new(&global_state, None, module_specifier.clone(), None, false)
.unwrap();
tokio_util::run_basic(async { 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; let result = worker.execute_module(&module_specifier).await;
if let Err(err) = result { if let Err(err) = result {
eprintln!("execute_mod err {:?}", err); eprintln!("execute_mod err {:?}", err);
@ -394,7 +421,7 @@ mod tests {
} }
}); });
// Check that we didn't start the compiler. // 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] #[test]
@ -406,11 +433,15 @@ mod tests {
let module_specifier = let module_specifier =
ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap(); ModuleSpecifier::resolve_url_or_path(&p.to_string_lossy()).unwrap();
let global_state = GlobalState::new(flags::Flags::default()).unwrap(); let global_state = GlobalState::new(flags::Flags::default()).unwrap();
let state = let global_state_ = global_state.clone();
CliState::new(&global_state, None, module_specifier.clone(), None, false)
.unwrap();
tokio_util::run_basic(async { 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; let result = worker.execute_module(&module_specifier).await;
if let Err(err) = result { if let Err(err) = result {
eprintln!("execute_mod err {:?}", err); eprintln!("execute_mod err {:?}", err);
@ -421,7 +452,7 @@ mod tests {
}); });
// Check that we didn't start the compiler. // 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] #[tokio::test]
@ -441,13 +472,12 @@ mod tests {
..flags::Flags::default() ..flags::Flags::default()
}; };
let global_state = GlobalState::new(flags).unwrap(); 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( let mut worker = MainWorker::new(
"TEST".to_string(), "TEST".to_string(),
Some(js::deno_isolate_init()), Some(js::deno_isolate_init()),
&state, global_state.permissions.clone(),
module_specifier.clone(),
global_state.clone(),
); );
worker.execute("bootstrap.mainRuntime()").unwrap(); worker.execute("bootstrap.mainRuntime()").unwrap();
let result = worker.execute_module(&module_specifier).await; let result = worker.execute_module(&module_specifier).await;
@ -458,15 +488,19 @@ mod tests {
panic!("Future got unexpected error: {:?}", e); panic!("Future got unexpected error: {:?}", e);
} }
// Check that we've only invoked the compiler once. // 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 { 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( let mut worker = MainWorker::new(
"TEST".to_string(), "TEST".to_string(),
Some(js::deno_isolate_init()), Some(js::deno_isolate_init()),
&state, Permissions::allow_all(),
main_module,
global_state,
); );
worker.execute("bootstrap.mainRuntime()").unwrap(); worker.execute("bootstrap.mainRuntime()").unwrap();
worker worker

View file

@ -5,10 +5,12 @@ use rusty_v8 as v8;
use crate::error::generic_error; use crate::error::generic_error;
use crate::error::AnyError; use crate::error::AnyError;
use crate::module_specifier::ModuleSpecifier; use crate::module_specifier::ModuleSpecifier;
use crate::OpState;
use futures::future::FutureExt; use futures::future::FutureExt;
use futures::stream::FuturesUnordered; use futures::stream::FuturesUnordered;
use futures::stream::Stream; use futures::stream::Stream;
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::future::Future; use std::future::Future;
@ -74,6 +76,7 @@ pub trait ModuleLoader {
/// dynamic imports altogether. /// dynamic imports altogether.
fn load( fn load(
&self, &self,
op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier, module_specifier: &ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>, maybe_referrer: Option<ModuleSpecifier>,
is_dyn_import: bool, is_dyn_import: bool,
@ -89,6 +92,7 @@ pub trait ModuleLoader {
/// It's not required to implement this method. /// It's not required to implement this method.
fn prepare_load( fn prepare_load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
_load_id: ModuleLoadId, _load_id: ModuleLoadId,
_module_specifier: &ModuleSpecifier, _module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<String>, _maybe_referrer: Option<String>,
@ -114,6 +118,7 @@ impl ModuleLoader for NoopModuleLoader {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
_module_specifier: &ModuleSpecifier, _module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,
@ -140,6 +145,7 @@ pub enum LoadState {
/// This future is used to implement parallel async module loading. /// This future is used to implement parallel async module loading.
pub struct RecursiveModuleLoad { pub struct RecursiveModuleLoad {
op_state: Rc<RefCell<OpState>>,
kind: Kind, kind: Kind,
// TODO(bartlomieju): in future this value should // TODO(bartlomieju): in future this value should
// be randomized // be randomized
@ -154,16 +160,18 @@ pub struct RecursiveModuleLoad {
impl RecursiveModuleLoad { impl RecursiveModuleLoad {
/// Starts a new parallel load of the given URL of the main module. /// Starts a new parallel load of the given URL of the main module.
pub fn main( pub fn main(
op_state: Rc<RefCell<OpState>>,
specifier: &str, specifier: &str,
code: Option<String>, code: Option<String>,
loader: Rc<dyn ModuleLoader>, loader: Rc<dyn ModuleLoader>,
) -> Self { ) -> Self {
let kind = Kind::Main; let kind = Kind::Main;
let state = LoadState::ResolveMain(specifier.to_owned(), code); let state = LoadState::ResolveMain(specifier.to_owned(), code);
Self::new(kind, state, loader) Self::new(op_state, kind, state, loader)
} }
pub fn dynamic_import( pub fn dynamic_import(
op_state: Rc<RefCell<OpState>>,
specifier: &str, specifier: &str,
referrer: &str, referrer: &str,
loader: Rc<dyn ModuleLoader>, loader: Rc<dyn ModuleLoader>,
@ -171,17 +179,23 @@ impl RecursiveModuleLoad {
let kind = Kind::DynamicImport; let kind = Kind::DynamicImport;
let state = let state =
LoadState::ResolveImport(specifier.to_owned(), referrer.to_owned()); 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 { pub fn is_dynamic_import(&self) -> bool {
self.kind != Kind::Main 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 { Self {
id: NEXT_LOAD_ID.fetch_add(1, Ordering::SeqCst), id: NEXT_LOAD_ID.fetch_add(1, Ordering::SeqCst),
root_module_id: None, root_module_id: None,
op_state,
kind, kind,
state, state,
loader, loader,
@ -212,6 +226,7 @@ impl RecursiveModuleLoad {
let prepare_result = self let prepare_result = self
.loader .loader
.prepare_load( .prepare_load(
self.op_state.clone(),
self.id, self.id,
&module_specifier, &module_specifier,
maybe_referrer, maybe_referrer,
@ -248,7 +263,12 @@ impl RecursiveModuleLoad {
} }
_ => self _ => self
.loader .loader
.load(&module_specifier, None, self.is_dynamic_import()) .load(
self.op_state.clone(),
&module_specifier,
None,
self.is_dynamic_import(),
)
.boxed_local(), .boxed_local(),
}; };
@ -264,10 +284,12 @@ impl RecursiveModuleLoad {
referrer: ModuleSpecifier, referrer: ModuleSpecifier,
) { ) {
if !self.is_pending.contains(&specifier) { if !self.is_pending.contains(&specifier) {
let fut = let fut = self.loader.load(
self self.op_state.clone(),
.loader &specifier,
.load(&specifier, Some(referrer), self.is_dynamic_import()); Some(referrer),
self.is_dynamic_import(),
);
self.pending.push(fut.boxed_local()); self.pending.push(fut.boxed_local());
self.is_pending.insert(specifier); self.is_pending.insert(specifier);
} }
@ -577,6 +599,7 @@ mod tests {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier, module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,

View file

@ -624,6 +624,7 @@ impl JsRuntimeState {
debug!("dyn_import specifier {} referrer {} ", specifier, referrer); debug!("dyn_import specifier {} referrer {} ", specifier, referrer);
let load = RecursiveModuleLoad::dynamic_import( let load = RecursiveModuleLoad::dynamic_import(
self.op_state.clone(),
specifier, specifier,
referrer, referrer,
self.loader.clone(), self.loader.clone(),
@ -1207,7 +1208,12 @@ impl JsRuntime {
state.loader.clone() 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 (_load_id, prepare_result) = load.prepare().await;
let mut load = prepare_result?; let mut load = prepare_result?;
@ -1890,6 +1896,7 @@ pub mod tests {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
_module_specifier: &ModuleSpecifier, _module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,
@ -1999,6 +2006,7 @@ pub mod tests {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
_module_specifier: &ModuleSpecifier, _module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,
@ -2059,6 +2067,7 @@ pub mod tests {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
specifier: &ModuleSpecifier, specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,
@ -2074,6 +2083,7 @@ pub mod tests {
fn prepare_load( fn prepare_load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
_load_id: ModuleLoadId, _load_id: ModuleLoadId,
_module_specifier: &ModuleSpecifier, _module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<String>, _maybe_referrer: Option<String>,
@ -2179,6 +2189,7 @@ pub mod tests {
fn load( fn load(
&self, &self,
_op_state: Rc<RefCell<OpState>>,
_module_specifier: &ModuleSpecifier, _module_specifier: &ModuleSpecifier,
_maybe_referrer: Option<ModuleSpecifier>, _maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool, _is_dyn_import: bool,

View file

@ -114,9 +114,7 @@ where
{ {
let state_ = state.borrow(); let state_ = state.borrow();
// TODO(ry) The Rc below is a hack because we store Rc<CliState> in OpState. let permissions = state_.borrow::<FP>();
// Ideally it could be removed.
let permissions = state_.borrow::<Rc<FP>>();
permissions.check_net_url(&url_)?; permissions.check_net_url(&url_)?;
} }
@ -221,9 +219,7 @@ where
let args: CreateHttpClientOptions = serde_json::from_value(args)?; let args: CreateHttpClientOptions = serde_json::from_value(args)?;
if let Some(ca_file) = args.ca_file.clone() { if let Some(ca_file) = args.ca_file.clone() {
// TODO(ry) The Rc below is a hack because we store Rc<CliState> in OpState. let permissions = state.borrow::<FP>();
// Ideally it could be removed.
let permissions = state.borrow::<Rc<FP>>();
permissions.check_read(&PathBuf::from(ca_file))?; permissions.check_read(&PathBuf::from(ca_file))?;
} }