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", 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 { itest!(import_compression {
args: "run --quiet --reload --allow-net run/import_compression/main.ts", args: "run --quiet --reload --allow-net run/import_compression/main.ts",
output: "run/import_compression/main.out", 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` // NOTE(bartlomieju): keep IDs in sync with `cli/main.rs`
const denoNsUnstableById = { const unstableIds = {
// BroadcastChannel is always available? broadcastChannel: 1,
// 1: {}, cron: 2,
ffi: 3,
2: { fs: 4,
cron: cron.cron, http: 5,
}, kv: 6,
net: 7,
// FFI unsafeProto: 8,
3: { workerOptions: 9,
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 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 // when editing this list, also update unstableDenoProps in cli/tsc/99_main_compiler.js
const denoNsUnstable = { const denoNsUnstable = {
listenDatagram: net.createListenDatagram( listenDatagram: net.createListenDatagram(
@ -242,4 +247,4 @@ const denoNsUnstable = {
cron: cron.cron, 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 webStorage from "ext:deno_webstorage/01_webstorage.js";
import * as prompt from "ext:runtime/41_prompt.js"; import * as prompt from "ext:runtime/41_prompt.js";
import * as imageData from "ext:deno_web/16_image_data.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 // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope
const windowOrWorkerGlobalScope = { const windowOrWorkerGlobalScope = {
@ -143,8 +144,11 @@ const windowOrWorkerGlobalScope = {
[webidl.brand]: util.nonEnumerable(webidl.brand), [webidl.brand]: util.nonEnumerable(webidl.brand),
}; };
const unstableWindowOrWorkerGlobalScope = { const unstableForWindowOrWorkerGlobalScope = {};
unstableForWindowOrWorkerGlobalScope[unstableIds.broadcastChannel] = {
BroadcastChannel: util.nonEnumerable(broadcastChannel.BroadcastChannel), BroadcastChannel: util.nonEnumerable(broadcastChannel.BroadcastChannel),
};
unstableForWindowOrWorkerGlobalScope[unstableIds.net] = {
WebSocketStream: util.nonEnumerable(webSocketStream.WebSocketStream), WebSocketStream: util.nonEnumerable(webSocketStream.WebSocketStream),
}; };
@ -312,7 +316,7 @@ const workerRuntimeGlobalProperties = {
export { export {
mainRuntimeGlobalProperties, mainRuntimeGlobalProperties,
memoizeLazy, memoizeLazy,
unstableWindowOrWorkerGlobalScope, unstableForWindowOrWorkerGlobalScope,
windowOrWorkerGlobalScope, windowOrWorkerGlobalScope,
workerRuntimeGlobalProperties, workerRuntimeGlobalProperties,
}; };

View file

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