1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-24 15:19:26 -05:00

fix(unstable): Honor granular unstable flags in js runtime (#21466)

This fixes #21434 for `BroadcastChannel` and `WebSocketStream`.
`--unstable` still enable both, but granular unstable flags now also
work:

* `--unstable-net` now enables `WebSocketStream`.
* `--unstable-broadcast-channel` now enables `BroadcastChannel`.
* Additionally, there are now tests for all granular unstable flags.
Since `unsafe-proto` already had tests, so I didn't add any for this
one.

It also introduces a map to keep track of granular unstable ids without
having to sync multiple places.
This commit is contained in:
Julien Cayzac 2023-12-08 22:24:49 +09:00 committed by GitHub
parent e15c735ede
commit ca64771257
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 414 additions and 68 deletions

View file

@ -1577,6 +1577,89 @@ itest!(unstable_worker {
output: "run/unstable_worker.ts.out",
});
itest!(unstable_worker_options_disabled {
args: "run --quiet --reload --allow-read run/unstable_worker_options.js",
output: "run/unstable_worker_options.disabled.out",
exit_code: 70,
});
itest!(unstable_worker_options_enabled {
args: "run --quiet --reload --allow-read --unstable-worker-options run/unstable_worker_options.js",
output: "run/unstable_worker_options.enabled.out",
});
itest!(unstable_broadcast_channel_disabled {
args: "run --quiet --reload --allow-read run/unstable_broadcast_channel.js",
output: "run/unstable_broadcast_channel.disabled.out",
});
itest!(unstable_broadcast_channel_enabled {
args: "run --quiet --reload --allow-read --unstable-broadcast-channel run/unstable_broadcast_channel.js",
output: "run/unstable_broadcast_channel.enabled.out",
});
itest!(unstable_cron_disabled {
args: "run --quiet --reload --allow-read run/unstable_cron.js",
output: "run/unstable_cron.disabled.out",
});
itest!(unstable_cron_enabled {
args:
"run --quiet --reload --allow-read --unstable-cron run/unstable_cron.js",
output: "run/unstable_cron.enabled.out",
});
itest!(unstable_ffi_disabled {
args: "run --quiet --reload --allow-read run/unstable_ffi.js",
output: "run/unstable_ffi.disabled.out",
});
itest!(unstable_ffi_enabled {
args: "run --quiet --reload --allow-read --unstable-ffi run/unstable_ffi.js",
output: "run/unstable_ffi.enabled.out",
});
itest!(unstable_fs_disabled {
args: "run --quiet --reload --allow-read run/unstable_fs.js",
output: "run/unstable_fs.disabled.out",
});
itest!(unstable_fs_enabled {
args: "run --quiet --reload --allow-read --unstable-fs run/unstable_fs.js",
output: "run/unstable_fs.enabled.out",
});
itest!(unstable_http_disabled {
args: "run --quiet --reload --allow-read run/unstable_http.js",
output: "run/unstable_http.disabled.out",
});
itest!(unstable_http_enabled {
args:
"run --quiet --reload --allow-read --unstable-http run/unstable_http.js",
output: "run/unstable_http.enabled.out",
});
itest!(unstable_net_disabled {
args: "run --quiet --reload --allow-read run/unstable_net.js",
output: "run/unstable_net.disabled.out",
});
itest!(unstable_net_enabled {
args: "run --quiet --reload --allow-read --unstable-net run/unstable_net.js",
output: "run/unstable_net.enabled.out",
});
itest!(unstable_kv_disabled {
args: "run --quiet --reload --allow-read run/unstable_kv.js",
output: "run/unstable_kv.disabled.out",
});
itest!(unstable_kv_enabled {
args: "run --quiet --reload --allow-read --unstable-kv run/unstable_kv.js",
output: "run/unstable_kv.enabled.out",
});
itest!(import_compression {
args: "run --quiet --reload --allow-net run/import_compression/main.ts",
output: "run/import_compression/main.out",

View file

@ -0,0 +1,2 @@
main undefined
worker undefined

View file

@ -0,0 +1,2 @@
main [class BroadcastChannel extends EventTarget]
worker [class BroadcastChannel extends EventTarget]

View file

@ -0,0 +1,10 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, globalThis.BroadcastChannel);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1,2 @@
main undefined
worker undefined

View file

@ -0,0 +1,2 @@
main [Function: cron]
worker [Function: cron]

10
cli/tests/testdata/run/unstable_cron.js vendored Normal file
View file

@ -0,0 +1,10 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, Deno.cron);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1,10 @@
main undefined
main undefined
main undefined
main undefined
main undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined

View file

@ -0,0 +1,10 @@
main [class UnsafeCallback]
main [class UnsafeFnPointer]
main [class UnsafePointer]
main [class UnsafePointerView]
main [Function: dlopen]
worker [class UnsafeCallback]
worker [class UnsafeFnPointer]
worker [class UnsafePointer]
worker [class UnsafePointerView]
worker [Function: dlopen]

14
cli/tests/testdata/run/unstable_ffi.js vendored Normal file
View file

@ -0,0 +1,14 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, Deno.UnsafeCallback);
console.log(scope, Deno.UnsafeFnPointer);
console.log(scope, Deno.UnsafePointer);
console.log(scope, Deno.UnsafePointerView);
console.log(scope, Deno.dlopen);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1,10 @@
main undefined
main undefined
main undefined
main undefined
main undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined

View file

@ -0,0 +1,10 @@
main [AsyncFunction: flock]
main [Function: flockSync]
main [AsyncFunction: funlock]
main [Function: funlockSync]
main [Function: umask]
worker [AsyncFunction: flock]
worker [Function: flockSync]
worker [AsyncFunction: funlock]
worker [Function: funlockSync]
worker [Function: umask]

14
cli/tests/testdata/run/unstable_fs.js vendored Normal file
View file

@ -0,0 +1,14 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, Deno.flock);
console.log(scope, Deno.flockSync);
console.log(scope, Deno.funlock);
console.log(scope, Deno.funlockSync);
console.log(scope, Deno.umask);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1,16 @@
main undefined
main undefined
main undefined
main undefined
main undefined
main undefined
main undefined
main undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined

View file

@ -0,0 +1,16 @@
main [class HttpClient]
main [Function: createHttpClient]
main [class HttpConn]
main Symbol("[[associated_ws]]")
main [Function: serve]
main [Function: upgradeHttp]
main [Function: upgradeWebSocket]
main [Function: upgradeHttp]
worker [class HttpClient]
worker [Function: createHttpClient]
worker [class HttpConn]
worker Symbol("[[associated_ws]]")
worker [Function: serve]
worker [Function: upgradeHttp]
worker [Function: upgradeWebSocket]
worker [Function: upgradeHttp]

17
cli/tests/testdata/run/unstable_http.js vendored Normal file
View file

@ -0,0 +1,17 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, Deno.HttpClient);
console.log(scope, Deno.createHttpClient);
console.log(scope, Deno.http?.HttpConn);
console.log(scope, Deno.http?._ws);
console.log(scope, Deno.http?.serve);
console.log(scope, Deno.http?.upgradeHttp);
console.log(scope, Deno.http?.upgradeWebSocket);
console.log(scope, Deno.upgradeHttp);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1,10 @@
main undefined
main undefined
main undefined
main undefined
main undefined
worker undefined
worker undefined
worker undefined
worker undefined
worker undefined

View file

@ -0,0 +1,10 @@
main [class AtomicOperation]
main [class Kv]
main [class KvListIterator extends Object]
main [class KvU64]
main [AsyncFunction: openKv]
worker [class AtomicOperation]
worker [class Kv]
worker [class KvListIterator extends Object]
worker [class KvU64]
worker [AsyncFunction: openKv]

14
cli/tests/testdata/run/unstable_kv.js vendored Normal file
View file

@ -0,0 +1,14 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, Deno.AtomicOperation);
console.log(scope, Deno.Kv);
console.log(scope, Deno.KvListIterator);
console.log(scope, Deno.KvU64);
console.log(scope, Deno.openKv);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1,4 @@
main undefined
main undefined
worker undefined
worker undefined

View file

@ -0,0 +1,4 @@
main [Function: listenDatagram]
main [class WebSocketStream]
worker [Function: listenDatagram]
worker [class WebSocketStream]

11
cli/tests/testdata/run/unstable_net.js vendored Normal file
View file

@ -0,0 +1,11 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
console.log(scope, Deno.listenDatagram);
console.log(scope, globalThis.WebSocketStream);
if (scope === "worker") {
postMessage("done");
} else {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
}

View file

@ -0,0 +1 @@
Unstable API 'Worker.deno.permissions'. The --unstable flag must be provided.

View file

@ -0,0 +1,2 @@
main ok
worker ok

View file

@ -0,0 +1,19 @@
const scope = import.meta.url.slice(-7) === "#worker" ? "worker" : "main";
new Worker(`data:application/javascript;base64,${btoa(`postMessage("ok");`)}`, {
type: "module",
deno: {
permissions: {
read: true,
},
},
}).onmessage = ({ data }) => {
console.log(scope, data);
if (scope === "main") {
const worker = new Worker(`${import.meta.url}#worker`, { type: "module" });
worker.onmessage = () => Deno.exit(0);
} else {
postMessage("done");
}
};

View file

@ -155,64 +155,69 @@ const denoNs = {
};
// NOTE(bartlomieju): keep IDs in sync with `cli/main.rs`
const denoNsUnstableById = {
// BroadcastChannel is always available?
// 1: {},
2: {
cron: cron.cron,
},
// FFI
3: {
dlopen: ffi.dlopen,
UnsafeCallback: ffi.UnsafeCallback,
UnsafePointer: ffi.UnsafePointer,
UnsafePointerView: ffi.UnsafePointerView,
UnsafeFnPointer: ffi.UnsafeFnPointer,
},
// FS
4: {
flock: fs.flock,
flockSync: fs.flockSync,
funlock: fs.funlock,
funlockSync: fs.funlockSync,
umask: fs.umask,
},
// HTTP
5: {
HttpClient: httpClient.HttpClient,
createHttpClient: httpClient.createHttpClient,
// TODO(bartlomieju): why is it needed?
http,
upgradeHttp: http.upgradeHttp,
},
// KV
6: {
openKv: kv.openKv,
AtomicOperation: kv.AtomicOperation,
Kv: kv.Kv,
KvU64: kv.KvU64,
KvListIterator: kv.KvListIterator,
},
// net
7: {
listenDatagram: net.createListenDatagram(
ops.op_net_listen_udp,
ops.op_net_listen_unixpacket,
),
},
// Unsafe proto
// 8: {},
// Worker options
// 9: {}
const unstableIds = {
broadcastChannel: 1,
cron: 2,
ffi: 3,
fs: 4,
http: 5,
kv: 6,
net: 7,
unsafeProto: 8,
workerOptions: 9,
};
const denoNsUnstableById = {};
// denoNsUnstableById[unstableIds.broadcastChannel] = {}
denoNsUnstableById[unstableIds.cron] = {
cron: cron.cron,
};
denoNsUnstableById[unstableIds.ffi] = {
dlopen: ffi.dlopen,
UnsafeCallback: ffi.UnsafeCallback,
UnsafePointer: ffi.UnsafePointer,
UnsafePointerView: ffi.UnsafePointerView,
UnsafeFnPointer: ffi.UnsafeFnPointer,
};
denoNsUnstableById[unstableIds.fs] = {
flock: fs.flock,
flockSync: fs.flockSync,
funlock: fs.funlock,
funlockSync: fs.funlockSync,
umask: fs.umask,
};
denoNsUnstableById[unstableIds.http] = {
HttpClient: httpClient.HttpClient,
createHttpClient: httpClient.createHttpClient,
// TODO(bartlomieju): why is it needed?
http,
upgradeHttp: http.upgradeHttp,
};
denoNsUnstableById[unstableIds.kv] = {
openKv: kv.openKv,
AtomicOperation: kv.AtomicOperation,
Kv: kv.Kv,
KvU64: kv.KvU64,
KvListIterator: kv.KvListIterator,
};
denoNsUnstableById[unstableIds.net] = {
listenDatagram: net.createListenDatagram(
ops.op_net_listen_udp,
ops.op_net_listen_unixpacket,
),
};
// denoNsUnstableById[unstableIds.unsafeProto] = {}
// denoNsUnstableById[unstableIds.workerOptions] = {}
// when editing this list, also update unstableDenoProps in cli/tsc/99_main_compiler.js
const denoNsUnstable = {
listenDatagram: net.createListenDatagram(
@ -242,4 +247,4 @@ const denoNsUnstable = {
cron: cron.cron,
};
export { denoNs, denoNsUnstable, denoNsUnstableById };
export { denoNs, denoNsUnstable, denoNsUnstableById, unstableIds };

View file

@ -42,6 +42,7 @@ import * as globalInterfaces from "ext:deno_web/04_global_interfaces.js";
import * as webStorage from "ext:deno_webstorage/01_webstorage.js";
import * as prompt from "ext:runtime/41_prompt.js";
import * as imageData from "ext:deno_web/16_image_data.js";
import { unstableIds } from "ext:runtime/90_deno_ns.js";
// https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = {
@ -143,8 +144,11 @@ const windowOrWorkerGlobalScope = {
[webidl.brand]: util.nonEnumerable(webidl.brand),
};
const unstableWindowOrWorkerGlobalScope = {
const unstableForWindowOrWorkerGlobalScope = {};
unstableForWindowOrWorkerGlobalScope[unstableIds.broadcastChannel] = {
BroadcastChannel: util.nonEnumerable(broadcastChannel.BroadcastChannel),
};
unstableForWindowOrWorkerGlobalScope[unstableIds.net] = {
WebSocketStream: util.nonEnumerable(webSocketStream.WebSocketStream),
};
@ -312,7 +316,7 @@ const workerRuntimeGlobalProperties = {
export {
mainRuntimeGlobalProperties,
memoizeLazy,
unstableWindowOrWorkerGlobalScope,
unstableForWindowOrWorkerGlobalScope,
windowOrWorkerGlobalScope,
workerRuntimeGlobalProperties,
};

View file

@ -17,8 +17,10 @@ const {
ObjectAssign,
ObjectDefineProperties,
ObjectDefineProperty,
ObjectKeys,
ObjectPrototypeIsPrototypeOf,
ObjectSetPrototypeOf,
ObjectValues,
PromisePrototypeThen,
PromiseResolve,
Symbol,
@ -47,6 +49,7 @@ import {
denoNs,
denoNsUnstable,
denoNsUnstableById,
unstableIds,
} from "ext:runtime/90_deno_ns.js";
import { errors } from "ext:runtime/01_errors.js";
import * as webidl from "ext:deno_webidl/00_webidl.js";
@ -54,7 +57,7 @@ import DOMException from "ext:deno_web/01_dom_exception.js";
import {
mainRuntimeGlobalProperties,
memoizeLazy,
unstableWindowOrWorkerGlobalScope,
unstableForWindowOrWorkerGlobalScope,
windowOrWorkerGlobalScope,
workerRuntimeGlobalProperties,
} from "ext:runtime/98_global_scope.js";
@ -370,6 +373,35 @@ let hasBootstrapped = false;
delete globalThis.console;
// Set up global properties shared by main and worker runtime.
ObjectDefineProperties(globalThis, windowOrWorkerGlobalScope);
// Set up global properties shared by main and worker runtime that are exposed
// by unstable features if those are enabled.
function exposeUnstableFeaturesForWindowOrWorkerGlobalScope(options) {
const { unstableFlag, unstableFeatures } = options;
if (unstableFlag) {
const all = ObjectValues(unstableForWindowOrWorkerGlobalScope);
for (let i = 0; i <= all.length; i++) {
const props = all[i];
ObjectDefineProperties(globalThis, { ...props });
}
} else {
const featureIds = ArrayPrototypeMap(
ObjectKeys(
unstableForWindowOrWorkerGlobalScope,
),
(k) => k | 0,
);
for (let i = 0; i <= featureIds.length; i++) {
const featureId = featureIds[i];
if (ArrayPrototypeIncludes(unstableFeatures, featureId)) {
const props = unstableForWindowOrWorkerGlobalScope[featureId];
ObjectDefineProperties(globalThis, { ...props });
}
}
}
}
// FIXME(bartlomieju): temporarily add whole `Deno.core` to
// `Deno[Deno.internal]` namespace. It should be removed and only necessary
// methods should be left there.
@ -430,9 +462,10 @@ function bootstrapMainRuntime(runtimeOptions) {
location.setLocationHref(location_);
}
if (unstableFlag) {
ObjectDefineProperties(globalThis, unstableWindowOrWorkerGlobalScope);
}
exposeUnstableFeaturesForWindowOrWorkerGlobalScope({
unstableFlag,
unstableFeatures,
});
ObjectDefineProperties(globalThis, mainRuntimeGlobalProperties);
ObjectDefineProperties(globalThis, {
// TODO(bartlomieju): in the future we might want to change the
@ -501,7 +534,7 @@ function bootstrapMainRuntime(runtimeOptions) {
}
}
if (!ArrayPrototypeIncludes(unstableFeatures, /* unsafe-proto */ 8)) {
if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.unsafeProto)) {
// Removes the `__proto__` for security reasons.
// https://tc39.es/ecma262/#sec-get-object.prototype.__proto__
delete Object.prototype.__proto__;
@ -547,9 +580,10 @@ function bootstrapWorkerRuntime(
delete globalThis.nodeBootstrap;
hasBootstrapped = true;
if (unstableFlag) {
ObjectDefineProperties(globalThis, unstableWindowOrWorkerGlobalScope);
}
exposeUnstableFeaturesForWindowOrWorkerGlobalScope({
unstableFlag,
unstableFeatures,
});
ObjectDefineProperties(globalThis, workerRuntimeGlobalProperties);
ObjectDefineProperties(globalThis, {
name: util.writable(name),
@ -604,7 +638,7 @@ function bootstrapWorkerRuntime(
}
}
if (!ArrayPrototypeIncludes(unstableFeatures, /* unsafe-proto */ 8)) {
if (!ArrayPrototypeIncludes(unstableFeatures, unstableIds.unsafeProto)) {
// Removes the `__proto__` for security reasons.
// https://tc39.es/ecma262/#sec-get-object.prototype.__proto__
delete Object.prototype.__proto__;