summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/main.rs4
-rw-r--r--cli/msg.fbs1
-rw-r--r--cli/ops.rs8
-rw-r--r--cli/state.rs5
-rw-r--r--cli/worker.rs4
-rw-r--r--core/shared_queue.js6
-rw-r--r--js/compiler.ts2
-rw-r--r--js/core.ts2
-rw-r--r--js/globals.ts3
-rw-r--r--js/main.ts7
-rw-r--r--js/os.ts20
-rw-r--r--js/workers.ts31
-rw-r--r--tests/039_worker_deno_ns.test2
-rw-r--r--tests/039_worker_deno_ns.ts25
-rw-r--r--tests/039_worker_deno_ns.ts.out4
-rw-r--r--tests/039_worker_deno_ns/has_ns.ts10
-rw-r--r--tests/039_worker_deno_ns/maybe_ns.ts1
-rw-r--r--tests/039_worker_deno_ns/no_ns.ts10
18 files changed, 128 insertions, 17 deletions
diff --git a/cli/main.rs b/cli/main.rs
index d8d834e8f..ff757ed36 100644
--- a/cli/main.rs
+++ b/cli/main.rs
@@ -196,8 +196,10 @@ fn create_worker_and_state(
s.status(status, msg).expect("shell problem");
}
});
+ // TODO(kevinkassimo): maybe make include_deno_namespace also configurable?
let state =
- ThreadSafeState::new(flags, argv, ops::op_selector_std, progress).unwrap();
+ ThreadSafeState::new(flags, argv, ops::op_selector_std, progress, true)
+ .unwrap();
let worker = Worker::new(
"main".to_string(),
startup_data::deno_isolate_init(),
diff --git a/cli/msg.fbs b/cli/msg.fbs
index 014bfb7e9..8f6497afc 100644
--- a/cli/msg.fbs
+++ b/cli/msg.fbs
@@ -204,6 +204,7 @@ table FormatErrorRes {
// Create worker as host
table CreateWorker {
specifier: string;
+ include_deno_namespace: bool;
}
table CreateWorkerRes {
diff --git a/cli/ops.rs b/cli/ops.rs
index 0e90e19c4..06c4eae99 100644
--- a/cli/ops.rs
+++ b/cli/ops.rs
@@ -2069,6 +2069,10 @@ fn op_create_worker(
let cmd_id = base.cmd_id();
let inner = base.inner_as_create_worker().unwrap();
let specifier = inner.specifier().unwrap();
+ // Only include deno namespace if requested AND current worker
+ // has included namespace (to avoid escalation).
+ let include_deno_namespace =
+ inner.include_deno_namespace() && state.include_deno_namespace;
let parent_state = state.clone();
@@ -2077,13 +2081,15 @@ fn op_create_worker(
parent_state.argv.clone(),
op_selector_std,
parent_state.progress.clone(),
+ include_deno_namespace,
)?;
let rid = child_state.resource.rid;
let name = format!("USER-WORKER-{}", specifier);
+ let deno_main_call = format!("denoMain({})", include_deno_namespace);
let mut worker =
Worker::new(name, startup_data::deno_isolate_init(), child_state);
- worker.execute("denoMain()").unwrap();
+ worker.execute(&deno_main_call).unwrap();
worker.execute("workerMain()").unwrap();
let module_specifier = ModuleSpecifier::resolve_url_or_path(specifier)?;
diff --git a/cli/state.rs b/cli/state.rs
index 139584394..f4e3d9c84 100644
--- a/cli/state.rs
+++ b/cli/state.rs
@@ -84,6 +84,8 @@ pub struct State {
pub js_compiler: JsCompiler,
pub json_compiler: JsonCompiler,
pub ts_compiler: TsCompiler,
+
+ pub include_deno_namespace: bool,
}
impl Clone for ThreadSafeState {
@@ -151,6 +153,7 @@ impl ThreadSafeState {
argv_rest: Vec<String>,
dispatch_selector: ops::OpSelector,
progress: Progress,
+ include_deno_namespace: bool,
) -> Result<Self, ErrBox> {
let custom_root = env::var("DENO_DIR").map(String::into).ok();
@@ -223,6 +226,7 @@ impl ThreadSafeState {
ts_compiler,
js_compiler: JsCompiler {},
json_compiler: JsonCompiler {},
+ include_deno_namespace,
};
Ok(ThreadSafeState(Arc::new(state)))
@@ -302,6 +306,7 @@ impl ThreadSafeState {
argv,
ops::op_selector_std,
Progress::new(),
+ true,
)
.unwrap()
}
diff --git a/cli/worker.rs b/cli/worker.rs
index befc69f85..f18062836 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -126,6 +126,7 @@ mod tests {
argv,
op_selector_std,
Progress::new(),
+ true,
)
.unwrap();
let state_ = state.clone();
@@ -155,6 +156,7 @@ mod tests {
argv,
op_selector_std,
Progress::new(),
+ true,
)
.unwrap();
let state_ = state.clone();
@@ -182,7 +184,7 @@ mod tests {
let mut flags = flags::DenoFlags::default();
flags.reload = true;
let state =
- ThreadSafeState::new(flags, argv, op_selector_std, Progress::new())
+ ThreadSafeState::new(flags, argv, op_selector_std, Progress::new(), true)
.unwrap();
let state_ = state.clone();
tokio_util::run(lazy(move || {
diff --git a/core/shared_queue.js b/core/shared_queue.js
index 75f370ce4..d7ab382d6 100644
--- a/core/shared_queue.js
+++ b/core/shared_queue.js
@@ -29,8 +29,12 @@ SharedQueue Binary Layout
const INDEX_RECORDS = 3 + MAX_RECORDS;
const HEAD_INIT = 4 * INDEX_RECORDS;
+ // Available on start due to bindings.
const Deno = window[GLOBAL_NAMESPACE];
const core = Deno[CORE_NAMESPACE];
+ // Warning: DO NOT use window.Deno after this point.
+ // It is possible that the Deno namespace has been deleted.
+ // Use the above local Deno and core variable instead.
let sharedBytes;
let shared32;
@@ -165,7 +169,7 @@ SharedQueue Binary Layout
const success = push(control);
// If successful, don't use first argument of core.send.
const arg0 = success ? null : control;
- return window.Deno.core.send(arg0, zeroCopy);
+ return Deno.core.send(arg0, zeroCopy);
}
const denoCore = {
diff --git a/js/compiler.ts b/js/compiler.ts
index 4203f753b..6bda5a1ec 100644
--- a/js/compiler.ts
+++ b/js/compiler.ts
@@ -25,7 +25,7 @@ const console = new Console(core.print);
window.console = console;
window.workerMain = workerMain;
export default function denoMain(): void {
- os.start("TS");
+ os.start(true, "TS");
}
const ASSETS = "$asset$";
diff --git a/js/core.ts b/js/core.ts
index 03473ff3d..436ba7ccb 100644
--- a/js/core.ts
+++ b/js/core.ts
@@ -1,4 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { window } from "./window";
+// This allows us to access core in API even if we
+// dispose window.Deno
export const core = window.Deno.core as DenoCore;
diff --git a/js/globals.ts b/js/globals.ts
index 27cef3909..92e4662aa 100644
--- a/js/globals.ts
+++ b/js/globals.ts
@@ -32,7 +32,6 @@ import * as request from "./request";
// These imports are not exposed and therefore are fine to just import the
// symbols required.
import { core } from "./core";
-import { immutableDefine } from "./util";
// During the build process, augmentations to the variable `window` in this
// file are tracked and created as part of default library that is built into
@@ -71,7 +70,7 @@ window.window = window;
// This is the Deno namespace, it is handled differently from other window
// properties when building the runtime type library, as the whole module
// is flattened into a single namespace.
-immutableDefine(window, "Deno", deno);
+window.Deno = deno;
Object.freeze(window.Deno);
// Globally available functions and object instances.
diff --git a/js/main.ts b/js/main.ts
index 5687a6926..769f522a6 100644
--- a/js/main.ts
+++ b/js/main.ts
@@ -18,8 +18,11 @@ import { setLocation } from "./location";
// builtin modules
import * as deno from "./deno";
-export default function denoMain(name?: string): void {
- const startResMsg = os.start(name);
+export default function denoMain(
+ preserveDenoNamespace: boolean = true,
+ name?: string
+): void {
+ const startResMsg = os.start(preserveDenoNamespace, name);
setVersions(startResMsg.denoVersion()!, startResMsg.v8Version()!);
diff --git a/js/os.ts b/js/os.ts
index 558f47efd..e7d588a52 100644
--- a/js/os.ts
+++ b/js/os.ts
@@ -112,7 +112,10 @@ function sendStart(): msg.StartRes {
// This function bootstraps an environment within Deno, it is shared both by
// the runtime and the compiler environments.
// @internal
-export function start(source?: string): msg.StartRes {
+export function start(
+ preserveDenoNamespace = true,
+ source?: string
+): msg.StartRes {
core.setAsyncHandler(handleAsyncMsgFromRust);
// First we send an empty `Start` message to let the privileged side know we
@@ -124,9 +127,18 @@ export function start(source?: string): msg.StartRes {
setGlobals(startResMsg.pid(), startResMsg.noColor(), startResMsg.execPath()!);
- // Deno.core could ONLY be safely frozen here (not in globals.ts)
- // since shared_queue.js will modify core properties.
- Object.freeze(window.Deno.core);
+ if (preserveDenoNamespace) {
+ util.immutableDefine(window, "Deno", window.Deno);
+ // Deno.core could ONLY be safely frozen here (not in globals.ts)
+ // since shared_queue.js will modify core properties.
+ Object.freeze(window.Deno.core);
+ // core.sharedQueue is an object so we should also freeze it.
+ Object.freeze(window.Deno.core.sharedQueue);
+ } else {
+ // Remove window.Deno
+ delete window.Deno;
+ assert(window.Deno === undefined);
+ }
return startResMsg;
}
diff --git a/js/workers.ts b/js/workers.ts
index 1531b960b..f008ccecf 100644
--- a/js/workers.ts
+++ b/js/workers.ts
@@ -20,10 +20,17 @@ export function decodeMessage(dataIntArray: Uint8Array): any {
return JSON.parse(dataJson);
}
-function createWorker(specifier: string): number {
+function createWorker(
+ specifier: string,
+ includeDenoNamespace: boolean
+): number {
const builder = flatbuffers.createBuilder();
const specifier_ = builder.createString(specifier);
- const inner = msg.CreateWorker.createCreateWorker(builder, specifier_);
+ const inner = msg.CreateWorker.createCreateWorker(
+ builder,
+ specifier_,
+ includeDenoNamespace
+ );
const baseRes = sendSync(builder, msg.Any.CreateWorker, inner);
assert(baseRes != null);
assert(
@@ -149,6 +156,18 @@ export interface Worker {
closed: Promise<void>;
}
+// TODO(kevinkassimo): Maybe implement reasonable web worker options?
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
+export interface WorkerOptions {}
+
+/** Extended Deno Worker initialization options.
+ * `noDenoNamespace` hides global `window.Deno` namespace for
+ * spawned worker and nested workers spawned by it (default: false).
+ */
+export interface DenoWorkerOptions extends WorkerOptions {
+ noDenoNamespace?: boolean;
+}
+
export class WorkerImpl implements Worker {
private readonly rid: number;
private isClosing: boolean = false;
@@ -157,8 +176,12 @@ export class WorkerImpl implements Worker {
public onmessage?: (data: any) => void;
public onmessageerror?: () => void;
- constructor(specifier: string) {
- this.rid = createWorker(specifier);
+ constructor(specifier: string, options?: DenoWorkerOptions) {
+ let includeDenoNamespace = true;
+ if (options && options.noDenoNamespace) {
+ includeDenoNamespace = false;
+ }
+ this.rid = createWorker(specifier, includeDenoNamespace);
this.run();
this.isClosedPromise = hostGetWorkerClosed(this.rid);
this.isClosedPromise.then(
diff --git a/tests/039_worker_deno_ns.test b/tests/039_worker_deno_ns.test
new file mode 100644
index 000000000..da282cc7b
--- /dev/null
+++ b/tests/039_worker_deno_ns.test
@@ -0,0 +1,2 @@
+args: run --reload tests/039_worker_deno_ns.ts
+output: tests/039_worker_deno_ns.ts.out
diff --git a/tests/039_worker_deno_ns.ts b/tests/039_worker_deno_ns.ts
new file mode 100644
index 000000000..1c6830c22
--- /dev/null
+++ b/tests/039_worker_deno_ns.ts
@@ -0,0 +1,25 @@
+const w1 = new Worker("./tests/039_worker_deno_ns/has_ns.ts");
+const w2 = new Worker("./tests/039_worker_deno_ns/no_ns.ts", {
+ noDenoNamespace: true
+});
+let w1MsgCount = 0;
+let w2MsgCount = 0;
+w1.onmessage = (msg): void => {
+ console.log(msg.data);
+ w1MsgCount++;
+ if (w1MsgCount === 1) {
+ w1.postMessage("CONTINUE");
+ } else {
+ w2.postMessage("START");
+ }
+};
+w2.onmessage = (msg): void => {
+ console.log(msg.data);
+ w2MsgCount++;
+ if (w2MsgCount === 1) {
+ w2.postMessage("CONTINUE");
+ } else {
+ Deno.exit(0);
+ }
+};
+w1.postMessage("START");
diff --git a/tests/039_worker_deno_ns.ts.out b/tests/039_worker_deno_ns.ts.out
new file mode 100644
index 000000000..9b2f90099
--- /dev/null
+++ b/tests/039_worker_deno_ns.ts.out
@@ -0,0 +1,4 @@
+has_ns.ts: is window.Deno available: true
+[SPAWNED BY has_ns.ts] maybe_ns.ts: is window.Deno available: true
+no_ns.ts: is window.Deno available: false
+[SPAWNED BY no_ns.ts] maybe_ns.ts: is window.Deno available: false
diff --git a/tests/039_worker_deno_ns/has_ns.ts b/tests/039_worker_deno_ns/has_ns.ts
new file mode 100644
index 000000000..15e729f63
--- /dev/null
+++ b/tests/039_worker_deno_ns/has_ns.ts
@@ -0,0 +1,10 @@
+onmessage = (msg): void => {
+ if (msg.data === "START") {
+ postMessage("has_ns.ts: is window.Deno available: " + !!window.Deno);
+ } else {
+ const worker = new Worker("./tests/039_worker_deno_ns/maybe_ns.ts");
+ worker.onmessage = (msg): void => {
+ postMessage("[SPAWNED BY has_ns.ts] " + msg.data);
+ };
+ }
+};
diff --git a/tests/039_worker_deno_ns/maybe_ns.ts b/tests/039_worker_deno_ns/maybe_ns.ts
new file mode 100644
index 000000000..0bcbd1f97
--- /dev/null
+++ b/tests/039_worker_deno_ns/maybe_ns.ts
@@ -0,0 +1 @@
+postMessage("maybe_ns.ts: is window.Deno available: " + !!window.Deno);
diff --git a/tests/039_worker_deno_ns/no_ns.ts b/tests/039_worker_deno_ns/no_ns.ts
new file mode 100644
index 000000000..4cee98bea
--- /dev/null
+++ b/tests/039_worker_deno_ns/no_ns.ts
@@ -0,0 +1,10 @@
+onmessage = (msg): void => {
+ if (msg.data === "START") {
+ postMessage("no_ns.ts: is window.Deno available: " + !!window.Deno);
+ } else {
+ const worker = new Worker("./tests/039_worker_deno_ns/maybe_ns.ts");
+ worker.onmessage = (msg): void => {
+ postMessage("[SPAWNED BY no_ns.ts] " + msg.data);
+ };
+ }
+};