From 41b186722c17b2f0d78049803a37b5c78d3822e5 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Thu, 16 Mar 2023 00:21:53 +0800 Subject: [PATCH] lib: distinguish webidl interfaces with the extended property "Exposed" PR-URL: https://github.com/nodejs/node/pull/46809 Refs: https://github.com/nodejs/node/issues/42528 Reviewed-By: Matteo Collina Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Joyee Cheung --- .../{browser.js => web/exposed-wildcard.js} | 56 +++----------- .../bootstrap/web/exposed-window-or-worker.js | 47 ++++++++++++ lib/internal/process/pre_execution.js | 4 +- lib/internal/url.js | 75 +++++++++++-------- lib/internal/util.js | 23 ++++++ src/node_realm.cc | 7 +- 6 files changed, 131 insertions(+), 81 deletions(-) rename lib/internal/bootstrap/{browser.js => web/exposed-wildcard.js} (64%) create mode 100644 lib/internal/bootstrap/web/exposed-window-or-worker.js diff --git a/lib/internal/bootstrap/browser.js b/lib/internal/bootstrap/web/exposed-wildcard.js similarity index 64% rename from lib/internal/bootstrap/browser.js rename to lib/internal/bootstrap/web/exposed-wildcard.js index 503b0208ca83d5..7d9b75caab667f 100644 --- a/lib/internal/bootstrap/browser.js +++ b/lib/internal/bootstrap/web/exposed-wildcard.js @@ -1,17 +1,21 @@ 'use strict'; +/** + * This file exposes web interfaces that is defined with the WebIDL + * [Exposed=*] extended attribute. + * See more details at https://webidl.spec.whatwg.org/#Exposed. + */ + const { - ObjectDefineProperty, globalThis, } = primordials; const { - defineOperation, exposeInterface, lazyDOMExceptionClass, - defineLazyProperties, - defineReplaceableLazyAttribute, exposeLazyInterfaces, + exposeGetterAndSetter, + exposeNamespace, } = require('internal/util'); const config = internalBinding('config'); @@ -35,36 +39,17 @@ exposeGetterAndSetter(globalThis, exposeInterface(globalThis, 'DOMException', value); }); -// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope -const timers = require('timers'); -defineOperation(globalThis, 'clearInterval', timers.clearInterval); -defineOperation(globalThis, 'clearTimeout', timers.clearTimeout); -defineOperation(globalThis, 'setInterval', timers.setInterval); -defineOperation(globalThis, 'setTimeout', timers.setTimeout); - +// https://dom.spec.whatwg.org/#interface-abortcontroller // Lazy ones. -exposeLazyInterfaces(globalThis, 'internal/worker/io', ['BroadcastChannel']); exposeLazyInterfaces(globalThis, 'internal/abort_controller', [ 'AbortController', 'AbortSignal', ]); +// https://dom.spec.whatwg.org/#interface-eventtarget const { EventTarget, Event, } = require('internal/event_target'); exposeInterface(globalThis, 'Event', Event); exposeInterface(globalThis, 'EventTarget', EventTarget); -exposeLazyInterfaces(globalThis, 'internal/worker/io', [ - 'MessageChannel', 'MessagePort', 'MessageEvent', -]); -defineLazyProperties(globalThis, 'buffer', ['atob', 'btoa']); -// https://www.w3.org/TR/FileAPI/#dfn-Blob -exposeLazyInterfaces(globalThis, 'internal/blob', ['Blob']); -// https://www.w3.org/TR/hr-time-2/#the-performance-attribute -exposeLazyInterfaces(globalThis, 'perf_hooks', [ - 'Performance', 'PerformanceEntry', 'PerformanceMark', 'PerformanceMeasure', - 'PerformanceObserver', 'PerformanceObserverEntryList', 'PerformanceResourceTiming', -]); - -defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']); // https://encoding.spec.whatwg.org/#textencoder // https://encoding.spec.whatwg.org/#textdecoder @@ -87,27 +72,6 @@ function createGlobalConsole() { return consoleFromNode; } -// https://heycam.github.io/webidl/#es-namespaces -function exposeNamespace(target, name, namespaceObject) { - ObjectDefineProperty(target, name, { - __proto__: null, - writable: true, - enumerable: false, - configurable: true, - value: namespaceObject, - }); -} - -function exposeGetterAndSetter(target, name, getter, setter = undefined) { - ObjectDefineProperty(target, name, { - __proto__: null, - enumerable: false, - configurable: true, - get: getter, - set: setter, - }); -} - // Web Streams API exposeLazyInterfaces( globalThis, diff --git a/lib/internal/bootstrap/web/exposed-window-or-worker.js b/lib/internal/bootstrap/web/exposed-window-or-worker.js new file mode 100644 index 00000000000000..ec4671dcd83474 --- /dev/null +++ b/lib/internal/bootstrap/web/exposed-window-or-worker.js @@ -0,0 +1,47 @@ +'use strict'; + +/** + * This file exposes web interfaces that is defined with the WebIDL + * Exposed=(Window,Worker) extended attribute or exposed in + * WindowOrWorkerGlobalScope mixin. + * See more details at https://webidl.spec.whatwg.org/#Exposed and + * https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope. + */ + +const { + globalThis, +} = primordials; + +const { + defineOperation, + defineLazyProperties, + defineReplaceableLazyAttribute, + exposeLazyInterfaces, +} = require('internal/util'); + +// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope +const timers = require('timers'); +defineOperation(globalThis, 'clearInterval', timers.clearInterval); +defineOperation(globalThis, 'clearTimeout', timers.clearTimeout); +defineOperation(globalThis, 'setInterval', timers.setInterval); +defineOperation(globalThis, 'setTimeout', timers.setTimeout); + +// https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts +exposeLazyInterfaces(globalThis, 'internal/worker/io', ['BroadcastChannel']); +exposeLazyInterfaces(globalThis, 'internal/worker/io', [ + 'MessageChannel', 'MessagePort', 'MessageEvent', +]); +defineLazyProperties(globalThis, 'buffer', ['atob', 'btoa']); +// https://www.w3.org/TR/FileAPI/#dfn-Blob +exposeLazyInterfaces(globalThis, 'internal/blob', ['Blob']); +// https://www.w3.org/TR/hr-time-2/#the-performance-attribute +exposeLazyInterfaces(globalThis, 'perf_hooks', [ + 'Performance', 'PerformanceEntry', 'PerformanceMark', 'PerformanceMeasure', + 'PerformanceObserver', 'PerformanceObserverEntryList', 'PerformanceResourceTiming', +]); + +defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']); + +// https://w3c.github.io/FileAPI/#creating-revoking +const { installObjectURLMethods } = require('internal/url'); +installObjectURLMethods(); diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js index 7dcbe07e65c68e..c7d0def209762f 100644 --- a/lib/internal/process/pre_execution.js +++ b/lib/internal/process/pre_execution.js @@ -268,7 +268,7 @@ function setupFetch() { }); } -// TODO(aduh95): move this to internal/bootstrap/browser when the CLI flag is +// TODO(aduh95): move this to internal/bootstrap/web/* when the CLI flag is // removed. function setupWebCrypto() { if (process.config.variables.node_no_browser_globals || @@ -316,7 +316,7 @@ function setupCodeCoverage() { } } -// TODO(daeyeon): move this to internal/bootstrap/browser when the CLI flag is +// TODO(daeyeon): move this to internal/bootstrap/web/* when the CLI flag is // removed. function setupCustomEvent() { if (process.config.variables.node_no_browser_globals || diff --git a/lib/internal/url.js b/lib/internal/url.js index 3a44c529876a08..2d8a84629464bc 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -91,11 +91,6 @@ const { updateUrl, } = internalBinding('url'); -const { - storeDataObject, - revokeDataObject, -} = internalBinding('blob'); - const FORWARD_SLASH = /\//g; const context = Symbol('context'); @@ -718,8 +713,33 @@ class URL { toJSON() { return this.#context.href; } +} + +ObjectDefineProperties(URL.prototype, { + [SymbolToStringTag]: { __proto__: null, configurable: true, value: 'URL' }, + toString: kEnumerableProperty, + href: kEnumerableProperty, + origin: kEnumerableProperty, + protocol: kEnumerableProperty, + username: kEnumerableProperty, + password: kEnumerableProperty, + host: kEnumerableProperty, + hostname: kEnumerableProperty, + port: kEnumerableProperty, + pathname: kEnumerableProperty, + search: kEnumerableProperty, + searchParams: kEnumerableProperty, + hash: kEnumerableProperty, + toJSON: kEnumerableProperty, +}); + +function installObjectURLMethods() { + const { + storeDataObject, + revokeDataObject, + } = internalBinding('blob'); - static createObjectURL(obj) { + function createObjectURL(obj) { const cryptoRandom = lazyCryptoRandom(); if (cryptoRandom === undefined) throw new ERR_NO_CRYPTO(); @@ -735,7 +755,7 @@ class URL { return `blob:nodedata:${id}`; } - static revokeObjectURL(url) { + function revokeObjectURL(url) { url = `${url}`; try { // TODO(@anonrig): Remove this try/catch by calling `parse` directly. @@ -747,30 +767,24 @@ class URL { // If there's an error, it's ignored. } } -} - -ObjectDefineProperties(URL.prototype, { - [SymbolToStringTag]: { __proto__: null, configurable: true, value: 'URL' }, - toString: kEnumerableProperty, - href: kEnumerableProperty, - origin: kEnumerableProperty, - protocol: kEnumerableProperty, - username: kEnumerableProperty, - password: kEnumerableProperty, - host: kEnumerableProperty, - hostname: kEnumerableProperty, - port: kEnumerableProperty, - pathname: kEnumerableProperty, - search: kEnumerableProperty, - searchParams: kEnumerableProperty, - hash: kEnumerableProperty, - toJSON: kEnumerableProperty, -}); -ObjectDefineProperties(URL, { - createObjectURL: kEnumerableProperty, - revokeObjectURL: kEnumerableProperty, -}); + ObjectDefineProperties(URL, { + createObjectURL: { + __proto__: null, + configurable: true, + writable: true, + enumerable: true, + value: createObjectURL, + }, + revokeObjectURL: { + __proto__: null, + configurable: true, + writable: true, + enumerable: true, + value: revokeObjectURL, + }, + }); +} // application/x-www-form-urlencoded parser // Ref: https://url.spec.whatwg.org/#concept-urlencoded-parser @@ -1251,6 +1265,7 @@ module.exports = { fileURLToPath, pathToFileURL, toPathIfFileURL, + installObjectURLMethods, URL, URLSearchParams, domainToASCII, diff --git a/lib/internal/util.js b/lib/internal/util.js index 64f329d28df6ed..1c8a02bd1811d8 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -511,6 +511,27 @@ function exposeInterface(target, name, interfaceObject) { }); } +// https://heycam.github.io/webidl/#es-namespaces +function exposeNamespace(target, name, namespaceObject) { + ObjectDefineProperty(target, name, { + __proto__: null, + writable: true, + enumerable: false, + configurable: true, + value: namespaceObject, + }); +} + +function exposeGetterAndSetter(target, name, getter, setter = undefined) { + ObjectDefineProperty(target, name, { + __proto__: null, + enumerable: false, + configurable: true, + get: getter, + set: setter, + }); +} + function defineLazyProperties(target, id, keys, enumerable = true) { const descriptors = { __proto__: null }; let mod; @@ -750,6 +771,8 @@ module.exports = { emitExperimentalWarning, exposeInterface, exposeLazyInterfaces, + exposeNamespace, + exposeGetterAndSetter, filterDuplicateStrings, filterOwnProperties, getConstructorOf, diff --git a/src/node_realm.cc b/src/node_realm.cc index ed141f3d6f4db2..ad6e22f6b5b35a 100644 --- a/src/node_realm.cc +++ b/src/node_realm.cc @@ -218,9 +218,10 @@ MaybeLocal Realm::BootstrapNode() { } if (!env_->no_browser_globals()) { - result = ExecuteBootstrapper("internal/bootstrap/browser"); - - if (result.IsEmpty()) { + if (ExecuteBootstrapper("internal/bootstrap/web/exposed-wildcard") + .IsEmpty() || + ExecuteBootstrapper("internal/bootstrap/web/exposed-window-or-worker") + .IsEmpty()) { return MaybeLocal(); } }