Skip to content

Commit

Permalink
lib: distinguish webidl interfaces with the extended property "Exposed"
Browse files Browse the repository at this point in the history
PR-URL: #46809
Refs: #42528
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
  • Loading branch information
legendecas committed Mar 15, 2023
1 parent d0153ae commit 41b1867
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -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');

Expand All @@ -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
Expand All @@ -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,
Expand Down
47 changes: 47 additions & 0 deletions lib/internal/bootstrap/web/exposed-window-or-worker.js
Original file line number Diff line number Diff line change
@@ -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();
4 changes: 2 additions & 2 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand Down Expand Up @@ -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 ||
Expand Down
75 changes: 45 additions & 30 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,6 @@ const {
updateUrl,
} = internalBinding('url');

const {
storeDataObject,
revokeDataObject,
} = internalBinding('blob');

const FORWARD_SLASH = /\//g;

const context = Symbol('context');
Expand Down Expand Up @@ -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();
Expand All @@ -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.
Expand All @@ -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
Expand Down Expand Up @@ -1251,6 +1265,7 @@ module.exports = {
fileURLToPath,
pathToFileURL,
toPathIfFileURL,
installObjectURLMethods,
URL,
URLSearchParams,
domainToASCII,
Expand Down
23 changes: 23 additions & 0 deletions lib/internal/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -750,6 +771,8 @@ module.exports = {
emitExperimentalWarning,
exposeInterface,
exposeLazyInterfaces,
exposeNamespace,
exposeGetterAndSetter,
filterDuplicateStrings,
filterOwnProperties,
getConstructorOf,
Expand Down
7 changes: 4 additions & 3 deletions src/node_realm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,10 @@ MaybeLocal<Value> 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<Value>();
}
}
Expand Down

0 comments on commit 41b1867

Please sign in to comment.