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::ModuleGraphLoader;
use crate::permissions::Permissions;
use crate::state::exit_unstable;
use crate::tsc::CompiledModule;
use crate::tsc::TargetLib;
use crate::tsc::TsCompiler;
@ -22,6 +21,14 @@ use std::sync::Arc;
use std::sync::Mutex;
use tokio::sync::Mutex as AsyncMutex;
pub fn exit_unstable(api_name: &str) {
eprintln!(
"Unstable API '{}'. The --unstable flag must be provided.",
api_name
);
std::process::exit(70);
}
/// This structure represents state of single "deno" program.
///
/// It is shared by all created workers (thus V8 isolates).
@ -235,6 +242,16 @@ impl GlobalState {
Ok(compiled_module)
}
/// Quits the process if the --unstable flag was not provided.
///
/// This is intentionally a non-recoverable check so that people cannot probe
/// for unstable APIs from stable programs.
pub fn check_unstable(&self, api_name: &str) {
if !self.flags.unstable {
exit_unstable(api_name);
}
}
#[cfg(test)]
pub fn mock(
argv: Vec<String>,

View file

@ -1,47 +1 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
//! This module helps deno implement timers.
//!
//! As an optimization, we want to avoid an expensive calls into rust for every
//! setTimeout in JavaScript. Thus in //js/timers.ts a data structure is
//! implemented that calls into Rust for only the smallest timeout. Thus we
//! only need to be able to start and cancel a single timer (or Delay, as Tokio
//! calls it) for an entire Isolate. This is what is implemented here.
use futures::channel::oneshot;
use futures::future::FutureExt;
use futures::TryFutureExt;
use std::future::Future;
use std::time::Instant;
#[derive(Default)]
pub struct GlobalTimer {
tx: Option<oneshot::Sender<()>>,
}
impl GlobalTimer {
pub fn cancel(&mut self) {
if let Some(tx) = self.tx.take() {
tx.send(()).ok();
}
}
pub fn new_timeout(
&mut self,
deadline: Instant,
) -> impl Future<Output = Result<(), ()>> {
if self.tx.is_some() {
self.cancel();
}
assert!(self.tx.is_none());
let (tx, rx) = oneshot::channel();
self.tx = Some(tx);
let delay = tokio::time::delay_until(deadline.into());
let rx = rx
.map_err(|err| panic!("Unexpected error in receiving channel {:?}", err));
futures::future::select(delay, rx).then(|_| futures::future::ok(()))
}
}

View file

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

View file

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

View file

@ -1,12 +1,12 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::state::CliState;
use crate::permissions::Permissions;
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_async(rt, "op_fetch", deno_fetch::op_fetch::<CliState>);
super::reg_json_async(rt, "op_fetch", deno_fetch::op_fetch::<Permissions>);
super::reg_json_async(rt, "op_fetch_read", deno_fetch::op_fetch_read);
super::reg_json_sync(
rt,
"op_create_http_client",
deno_fetch::op_create_http_client::<CliState>,
deno_fetch::op_create_http_client::<Permissions>,
);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,17 +1,61 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::global_timer::GlobalTimer;
//! This module helps deno implement timers.
//!
//! As an optimization, we want to avoid an expensive calls into rust for every
//! setTimeout in JavaScript. Thus in //js/timers.ts a data structure is
//! implemented that calls into Rust for only the smallest timeout. Thus we
//! only need to be able to start and cancel a single timer (or Delay, as Tokio
//! calls it) for an entire Isolate. This is what is implemented here.
use crate::permissions::Permissions;
use deno_core::error::AnyError;
use deno_core::BufVec;
use deno_core::OpState;
use deno_core::ZeroCopyBuf;
use futures::future::FutureExt;
use futures::channel::oneshot;
use futures::FutureExt;
use futures::TryFutureExt;
use serde::Deserialize;
use serde_json::Value;
use std::cell::RefCell;
use std::future::Future;
use std::rc::Rc;
use std::time::Duration;
use std::time::Instant;
pub type StartTime = Instant;
#[derive(Default)]
pub struct GlobalTimer {
tx: Option<oneshot::Sender<()>>,
}
impl GlobalTimer {
pub fn cancel(&mut self) {
if let Some(tx) = self.tx.take() {
tx.send(()).ok();
}
}
pub fn new_timeout(
&mut self,
deadline: Instant,
) -> impl Future<Output = Result<(), ()>> {
if self.tx.is_some() {
self.cancel();
}
assert!(self.tx.is_none());
let (tx, rx) = oneshot::channel();
self.tx = Some(tx);
let delay = tokio::time::delay_until(deadline.into());
let rx = rx
.map_err(|err| panic!("Unexpected error in receiving channel {:?}", err));
futures::future::select(delay, rx).then(|_| futures::future::ok(()))
}
}
pub fn init(rt: &mut deno_core::JsRuntime) {
super::reg_json_sync(rt, "op_global_timer_stop", op_global_timer_stop);
@ -61,15 +105,15 @@ fn op_now(
_args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> {
let cli_state = super::cli_state(state);
let seconds = cli_state.start_time.elapsed().as_secs();
let mut subsec_nanos = cli_state.start_time.elapsed().subsec_nanos();
let start_time = state.borrow::<StartTime>();
let seconds = start_time.elapsed().as_secs();
let mut subsec_nanos = start_time.elapsed().subsec_nanos();
let reduced_time_precision = 2_000_000; // 2ms in nanoseconds
// If the permission is not enabled
// Round the nano result on 2 milliseconds
// see: https://developer.mozilla.org/en-US/docs/Web/API/DOMHighResTimeStamp#Reduced_time_precision
if cli_state.check_hrtime().is_err() {
if state.borrow::<Permissions>().check_hrtime().is_err() {
subsec_nanos -= subsec_nanos % reduced_time_precision;
}

View file

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

View file

@ -62,7 +62,7 @@ fn op_set_raw(
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> {
super::cli_state(state).check_unstable("Deno.setRaw");
super::global_state(state).check_unstable("Deno.setRaw");
let args: SetRawArgs = serde_json::from_value(args)?;
let rid = args.rid;
@ -273,7 +273,7 @@ fn op_console_size(
args: Value,
_zero_copy: &mut [ZeroCopyBuf],
) -> Result<Value, AnyError> {
super::cli_state(state).check_unstable("Deno.consoleSize");
super::global_state(state).check_unstable("Deno.consoleSize");
let args: ConsoleSizeArgs = serde_json::from_value(args)?;
let rid = args.rid;

View file

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

View file

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

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.
/// This loops until the user gives the proper input.
#[cfg(not(test))]

View file

@ -1,58 +1,49 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use crate::file_fetcher::SourceFileFetcher;
use crate::global_state::GlobalState;
use crate::import_map::ImportMap;
use crate::permissions::Permissions;
use crate::tsc::TargetLib;
use crate::web_worker::WebWorkerHandle;
use deno_core::error::AnyError;
use deno_core::url;
use deno_core::ModuleLoadId;
use deno_core::ModuleLoader;
use deno_core::ModuleSpecifier;
use deno_core::OpState;
use futures::future::FutureExt;
use futures::Future;
use std::cell::Cell;
use std::cell::RefCell;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::pin::Pin;
use std::rc::Rc;
use std::str;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::time::Instant;
// This is named "CliState" instead of just "State" to avoid confusion with all
// other state structs (GlobalState, OpState, GothamState).
// TODO(ry) Many of the items in this struct should be moved out and into
// OpState, removing redundant RefCell wrappers if possible.
pub struct CliState {
pub global_state: Arc<GlobalState>,
pub permissions: RefCell<Permissions>,
pub main_module: ModuleSpecifier,
pub struct CliModuleLoader {
/// When flags contains a `.import_map_path` option, the content of the
/// import map file will be resolved and set.
pub import_map: Option<ImportMap>,
pub workers: RefCell<HashMap<u32, (JoinHandle<()>, WebWorkerHandle)>>,
pub next_worker_id: Cell<u32>,
pub start_time: Instant,
pub target_lib: TargetLib,
pub is_main: bool,
pub is_internal: bool,
}
pub fn exit_unstable(api_name: &str) {
eprintln!(
"Unstable API '{}'. The --unstable flag must be provided.",
api_name
);
std::process::exit(70);
impl CliModuleLoader {
pub fn new(maybe_import_map: Option<ImportMap>) -> Rc<Self> {
Rc::new(CliModuleLoader {
import_map: maybe_import_map,
target_lib: TargetLib::Main,
is_main: true,
})
}
pub fn new_for_worker() -> Rc<Self> {
Rc::new(CliModuleLoader {
import_map: None,
target_lib: TargetLib::Worker,
is_main: false,
})
}
}
impl ModuleLoader for CliState {
impl ModuleLoader for CliModuleLoader {
fn resolve(
&self,
specifier: &str,
@ -75,13 +66,17 @@ impl ModuleLoader for CliState {
fn load(
&self,
op_state: Rc<RefCell<OpState>>,
module_specifier: &ModuleSpecifier,
maybe_referrer: Option<ModuleSpecifier>,
_is_dyn_import: bool,
) -> Pin<Box<deno_core::ModuleSourceFuture>> {
let module_specifier = module_specifier.to_owned();
let module_url_specified = module_specifier.to_string();
let global_state = self.global_state.clone();
let global_state = {
let state = op_state.borrow();
state.borrow::<Arc<GlobalState>>().clone()
};
// TODO(bartlomieju): `fetch_compiled_module` should take `load_id` param
let fut = async move {
@ -102,6 +97,7 @@ impl ModuleLoader for CliState {
fn prepare_load(
&self,
op_state: Rc<RefCell<OpState>>,
_load_id: ModuleLoadId,
module_specifier: &ModuleSpecifier,
maybe_referrer: Option<String>,
@ -110,15 +106,19 @@ impl ModuleLoader for CliState {
let module_specifier = module_specifier.clone();
let target_lib = self.target_lib.clone();
let maybe_import_map = self.import_map.clone();
let state = op_state.borrow();
// Only "main" module is loaded without permission check,
// ie. module that is associated with "is_main" state
// and is not a dynamic import.
let permissions = if self.is_main && !is_dyn_import {
Permissions::allow_all()
} else {
self.permissions.borrow().clone()
state.borrow::<Permissions>().clone()
};
let global_state = self.global_state.clone();
let global_state = state.borrow::<Arc<GlobalState>>().clone();
drop(state);
// TODO(bartlomieju): I'm not sure if it's correct to ignore
// bad referrer - this is the case for `Deno.core.evalContext()` where
// `ref_str` is `<unknown>`.
@ -144,168 +144,3 @@ impl ModuleLoader for CliState {
.boxed_local()
}
}
impl CliState {
/// If `shared_permission` is None then permissions from globa state are used.
pub fn new(
global_state: &Arc<GlobalState>,
shared_permissions: Option<Permissions>,
main_module: ModuleSpecifier,
maybe_import_map: Option<ImportMap>,
is_internal: bool,
) -> Result<Rc<Self>, AnyError> {
let state = CliState {
global_state: global_state.clone(),
main_module,
permissions: shared_permissions
.unwrap_or_else(|| global_state.permissions.clone())
.into(),
import_map: maybe_import_map,
workers: Default::default(),
next_worker_id: Default::default(),
start_time: Instant::now(),
target_lib: TargetLib::Main,
is_main: true,
is_internal,
};
Ok(Rc::new(state))
}
/// If `shared_permission` is None then permissions from globa state are used.
pub fn new_for_worker(
global_state: &Arc<GlobalState>,
shared_permissions: Option<Permissions>,
main_module: ModuleSpecifier,
) -> Result<Rc<Self>, AnyError> {
let state = CliState {
global_state: global_state.clone(),
main_module,
permissions: shared_permissions
.unwrap_or_else(|| global_state.permissions.clone())
.into(),
import_map: None,
workers: Default::default(),
next_worker_id: Default::default(),
start_time: Instant::now(),
target_lib: TargetLib::Worker,
is_main: false,
is_internal: false,
};
Ok(Rc::new(state))
}
#[inline]
pub fn check_read(&self, path: &Path) -> Result<(), AnyError> {
self.permissions.borrow().check_read(path)
}
/// As `check_read()`, but permission error messages will anonymize the path
/// by replacing it with the given `display`.
#[inline]
pub fn check_read_blind(
&self,
path: &Path,
display: &str,
) -> Result<(), AnyError> {
self.permissions.borrow().check_read_blind(path, display)
}
#[inline]
pub fn check_write(&self, path: &Path) -> Result<(), AnyError> {
self.permissions.borrow().check_write(path)
}
#[inline]
pub fn check_env(&self) -> Result<(), AnyError> {
self.permissions.borrow().check_env()
}
#[inline]
pub fn check_net(&self, hostname: &str, port: u16) -> Result<(), AnyError> {
self.permissions.borrow().check_net(hostname, port)
}
#[inline]
pub fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> {
self.permissions.borrow().check_net_url(url)
}
#[inline]
pub fn check_run(&self) -> Result<(), AnyError> {
self.permissions.borrow().check_run()
}
#[inline]
pub fn check_hrtime(&self) -> Result<(), AnyError> {
self.permissions.borrow().check_hrtime()
}
#[inline]
pub fn check_plugin(&self, filename: &Path) -> Result<(), AnyError> {
self.permissions.borrow().check_plugin(filename)
}
pub fn check_dyn_import(
&self,
module_specifier: &ModuleSpecifier,
) -> Result<(), AnyError> {
let u = module_specifier.as_url();
// TODO(bartlomieju): temporary fix to prevent hitting `unreachable`
// statement that is actually reachable...
SourceFileFetcher::check_if_supported_scheme(u)?;
match u.scheme() {
"http" | "https" => {
self.check_net_url(u)?;
Ok(())
}
"file" => {
let path = u
.to_file_path()
.unwrap()
.into_os_string()
.into_string()
.unwrap();
self.check_read(Path::new(&path))?;
Ok(())
}
_ => unreachable!(),
}
}
#[cfg(test)]
pub fn mock(main_module: &str) -> Rc<Self> {
let module_specifier = ModuleSpecifier::resolve_url_or_path(main_module)
.expect("Invalid entry module");
CliState::new(
&GlobalState::mock(vec!["deno".to_string()], None),
None,
module_specifier,
None,
false,
)
.unwrap()
}
/// Quits the process if the --unstable flag was not provided.
///
/// This is intentionally a non-recoverable check so that people cannot probe
/// for unstable APIs from stable programs.
pub fn check_unstable(&self, api_name: &str) {
// TODO(ry) Maybe use IsolateHandle::terminate_execution here to provide a
// stack trace in JS.
if !self.global_state.flags.unstable {
exit_unstable(api_name);
}
}
}
impl deno_fetch::FetchPermissions for CliState {
fn check_net_url(&self, url: &url::Url) -> Result<(), AnyError> {
CliState::check_net_url(self, url)
}
fn check_read(&self, p: &PathBuf) -> Result<(), AnyError> {
CliState::check_read(self, p)
}
}

View file

@ -18,7 +18,7 @@ use crate::module_graph::ModuleGraphLoader;
use crate::ops;
use crate::permissions::Permissions;
use crate::source_maps::SourceMapGetter;
use crate::state::CliState;
use crate::state::CliModuleLoader;
use crate::tsc_config;
use crate::version;
use crate::worker::Worker;
@ -48,7 +48,6 @@ use std::ops::DerefMut;
use std::path::Path;
use std::path::PathBuf;
use std::pin::Pin;
use std::rc::Rc;
use std::str;
use std::sync::atomic::Ordering;
use std::sync::Arc;
@ -132,9 +131,25 @@ pub struct CompilerWorker {
}
impl CompilerWorker {
pub fn new(name: String, state: &Rc<CliState>) -> Self {
let mut worker =
Worker::new(name, Some(js::compiler_isolate_init()), state);
pub fn new(
name: String,
permissions: Permissions,
global_state: Arc<GlobalState>,
) -> Self {
let main_module =
ModuleSpecifier::resolve_url_or_path("./$deno$compiler.ts").unwrap();
// TODO(bartlomieju): compiler worker shouldn't require any loader/state
let loader = CliModuleLoader::new(None);
let mut worker = Worker::new(
name,
Some(js::compiler_isolate_init()),
permissions,
main_module,
global_state,
loader,
false,
true,
);
let response = Arc::new(Mutex::new(None));
ops::runtime::init(&mut worker);
ops::errors::init(&mut worker);
@ -215,17 +230,12 @@ fn create_compiler_worker(
global_state: &Arc<GlobalState>,
permissions: Permissions,
) -> CompilerWorker {
let entry_point =
ModuleSpecifier::resolve_url_or_path("./$deno$compiler.ts").unwrap();
let worker_state =
CliState::new(&global_state, Some(permissions), entry_point, None, true)
.expect("Unable to create worker state");
// TODO(bartlomieju): this metric is never used anywhere
// Count how many times we start the compiler worker.
global_state.compiler_starts.fetch_add(1, Ordering::SeqCst);
let mut worker = CompilerWorker::new("TS".to_string(), &worker_state);
let mut worker =
CompilerWorker::new("TS".to_string(), permissions, global_state.clone());
worker
.execute("globalThis.bootstrapCompilerRuntime()")
.unwrap();

View file

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

View file

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

View file

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

View file

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

View file

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