lib,src: support DOMException ser-des
Added serialization and deserialization support for `DOMException`. Co-Authored-By: jazelly <xzha4350@gmail.com> PR-URL: https://github.com/nodejs/node/pull/58649 Fixes: https://github.com/nodejs/node/issues/49181 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Jason Zhang <xzha4350@gmail.com>
This commit is contained in:
parent
3a7f8efe60
commit
5457443210
@ -525,4 +525,16 @@ export default [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'lib/internal/per_context/domexception.js',
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
// Parameters passed to internal modules.
|
||||||
|
privateSymbols: 'readonly',
|
||||||
|
perIsolateSymbols: 'readonly',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
@ -12,6 +12,18 @@ const {
|
|||||||
SymbolToStringTag,
|
SymbolToStringTag,
|
||||||
TypeError,
|
TypeError,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
const {
|
||||||
|
transfer_mode_private_symbol,
|
||||||
|
} = privateSymbols;
|
||||||
|
const {
|
||||||
|
messaging_clone_symbol,
|
||||||
|
messaging_deserialize_symbol,
|
||||||
|
} = perIsolateSymbols;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps to BaseObject::TransferMode::kCloneable
|
||||||
|
*/
|
||||||
|
const kCloneable = 2;
|
||||||
|
|
||||||
function throwInvalidThisError(Base, type) {
|
function throwInvalidThisError(Base, type) {
|
||||||
const err = new Base();
|
const err = new Base();
|
||||||
@ -50,6 +62,7 @@ const disusedNamesSet = new SafeSet()
|
|||||||
|
|
||||||
class DOMException {
|
class DOMException {
|
||||||
constructor(message = '', options = 'Error') {
|
constructor(message = '', options = 'Error') {
|
||||||
|
this[transfer_mode_private_symbol] = kCloneable;
|
||||||
ErrorCaptureStackTrace(this);
|
ErrorCaptureStackTrace(this);
|
||||||
|
|
||||||
if (options && typeof options === 'object') {
|
if (options && typeof options === 'object') {
|
||||||
@ -76,6 +89,28 @@ class DOMException {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[messaging_clone_symbol]() {
|
||||||
|
// See serialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception
|
||||||
|
const internals = internalsMap.get(this);
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
message: internals.message,
|
||||||
|
name: internals.name,
|
||||||
|
stack: this.stack,
|
||||||
|
},
|
||||||
|
deserializeInfo: 'internal/worker/clone_dom_exception:DOMException',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[messaging_deserialize_symbol](data) {
|
||||||
|
// See deserialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception
|
||||||
|
internalsMap.set(this, {
|
||||||
|
message: data.message,
|
||||||
|
name: data.name,
|
||||||
|
});
|
||||||
|
this.stack = data.stack;
|
||||||
|
}
|
||||||
|
|
||||||
get name() {
|
get name() {
|
||||||
const internals = internalsMap.get(this);
|
const internals = internalsMap.get(this);
|
||||||
if (internals === undefined) {
|
if (internals === undefined) {
|
||||||
|
6
lib/internal/worker/clone_dom_exception.js
Normal file
6
lib/internal/worker/clone_dom_exception.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
// Delegate to the actual DOMException implementation.
|
||||||
|
module.exports = {
|
||||||
|
DOMException: internalBinding('messaging').DOMException,
|
||||||
|
};
|
@ -767,13 +767,13 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
|
|||||||
Context::Scope context_scope(context);
|
Context::Scope context_scope(context);
|
||||||
|
|
||||||
Local<ObjectTemplate> private_symbols = ObjectTemplate::New(isolate);
|
Local<ObjectTemplate> private_symbols = ObjectTemplate::New(isolate);
|
||||||
Local<Object> private_symbols_object;
|
|
||||||
#define V(PropertyName, _) \
|
#define V(PropertyName, _) \
|
||||||
private_symbols->Set(isolate, #PropertyName, isolate_data->PropertyName());
|
private_symbols->Set(isolate, #PropertyName, isolate_data->PropertyName());
|
||||||
|
|
||||||
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
|
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
|
Local<Object> private_symbols_object;
|
||||||
if (!private_symbols->NewInstance(context).ToLocal(&private_symbols_object) ||
|
if (!private_symbols->NewInstance(context).ToLocal(&private_symbols_object) ||
|
||||||
private_symbols_object->SetPrototypeV2(context, Null(isolate))
|
private_symbols_object->SetPrototypeV2(context, Null(isolate))
|
||||||
.IsNothing()) {
|
.IsNothing()) {
|
||||||
@ -783,6 +783,32 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
|
|||||||
return scope.Escape(private_symbols_object);
|
return scope.Escape(private_symbols_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
|
||||||
|
IsolateData* isolate_data) {
|
||||||
|
CHECK(isolate_data);
|
||||||
|
Isolate* isolate = context->GetIsolate();
|
||||||
|
EscapableHandleScope scope(isolate);
|
||||||
|
Context::Scope context_scope(context);
|
||||||
|
|
||||||
|
Local<ObjectTemplate> per_isolate_symbols = ObjectTemplate::New(isolate);
|
||||||
|
#define V(PropertyName, _) \
|
||||||
|
per_isolate_symbols->Set( \
|
||||||
|
isolate, #PropertyName, isolate_data->PropertyName());
|
||||||
|
|
||||||
|
PER_ISOLATE_SYMBOL_PROPERTIES(V)
|
||||||
|
#undef V
|
||||||
|
|
||||||
|
Local<Object> per_isolate_symbols_object;
|
||||||
|
if (!per_isolate_symbols->NewInstance(context).ToLocal(
|
||||||
|
&per_isolate_symbols_object) ||
|
||||||
|
per_isolate_symbols_object->SetPrototypeV2(context, Null(isolate))
|
||||||
|
.IsNothing()) {
|
||||||
|
return MaybeLocal<Object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return scope.Escape(per_isolate_symbols_object);
|
||||||
|
}
|
||||||
|
|
||||||
Maybe<void> InitializePrimordials(Local<Context> context,
|
Maybe<void> InitializePrimordials(Local<Context> context,
|
||||||
IsolateData* isolate_data) {
|
IsolateData* isolate_data) {
|
||||||
// Run per-context JS files.
|
// Run per-context JS files.
|
||||||
@ -812,6 +838,12 @@ Maybe<void> InitializePrimordials(Local<Context> context,
|
|||||||
return Nothing<void>();
|
return Nothing<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Local<Object> per_isolate_symbols;
|
||||||
|
if (!InitializePerIsolateSymbols(context, isolate_data)
|
||||||
|
.ToLocal(&per_isolate_symbols)) {
|
||||||
|
return Nothing<void>();
|
||||||
|
}
|
||||||
|
|
||||||
static const char* context_files[] = {"internal/per_context/primordials",
|
static const char* context_files[] = {"internal/per_context/primordials",
|
||||||
"internal/per_context/domexception",
|
"internal/per_context/domexception",
|
||||||
"internal/per_context/messageport",
|
"internal/per_context/messageport",
|
||||||
@ -827,7 +859,8 @@ Maybe<void> InitializePrimordials(Local<Context> context,
|
|||||||
builtin_loader.SetEagerCompile();
|
builtin_loader.SetEagerCompile();
|
||||||
|
|
||||||
for (const char** module = context_files; *module != nullptr; module++) {
|
for (const char** module = context_files; *module != nullptr; module++) {
|
||||||
Local<Value> arguments[] = {exports, primordials, private_symbols};
|
Local<Value> arguments[] = {
|
||||||
|
exports, primordials, private_symbols, per_isolate_symbols};
|
||||||
|
|
||||||
if (builtin_loader
|
if (builtin_loader
|
||||||
.CompileAndCall(
|
.CompileAndCall(
|
||||||
|
@ -416,6 +416,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
|
|||||||
FIXED_ONE_BYTE_STRING(isolate, "exports"),
|
FIXED_ONE_BYTE_STRING(isolate, "exports"),
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "primordials"),
|
FIXED_ONE_BYTE_STRING(isolate, "primordials"),
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "privateSymbols"),
|
FIXED_ONE_BYTE_STRING(isolate, "privateSymbols"),
|
||||||
|
FIXED_ONE_BYTE_STRING(isolate, "perIsolateSymbols"),
|
||||||
};
|
};
|
||||||
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
|
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
|
||||||
strncmp(id,
|
strncmp(id,
|
||||||
|
48
test/parallel/test-structuredClone-domexception.js
Normal file
48
test/parallel/test-structuredClone-domexception.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('../common');
|
||||||
|
const assert = require('assert');
|
||||||
|
|
||||||
|
function assertDOMException(actual, expected) {
|
||||||
|
assert.strictEqual(actual instanceof DOMException, true);
|
||||||
|
assert.strictEqual(actual.message, expected.message);
|
||||||
|
assert.strictEqual(actual.name, expected.name);
|
||||||
|
assert.strictEqual(actual.code, expected.code);
|
||||||
|
assert.strictEqual(actual.stack, expected.stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Clone basic DOMException
|
||||||
|
const e = new DOMException('test');
|
||||||
|
const clone = structuredClone(e);
|
||||||
|
const clone2 = structuredClone(clone);
|
||||||
|
assertDOMException(clone, e);
|
||||||
|
assertDOMException(clone2, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Clone a DOMException with a name
|
||||||
|
const e = new DOMException('test', 'DataCloneError');
|
||||||
|
const clone = structuredClone(e);
|
||||||
|
const clone2 = structuredClone(clone);
|
||||||
|
assertDOMException(clone, e);
|
||||||
|
assertDOMException(clone2, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Clone an arbitrary object with a DOMException prototype
|
||||||
|
const obj = {};
|
||||||
|
Object.setPrototypeOf(obj, DOMException.prototype);
|
||||||
|
const clone = structuredClone(obj);
|
||||||
|
assert.strictEqual(clone instanceof DOMException, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Transfer a DOMException. DOMExceptions are not transferable.
|
||||||
|
const e = new DOMException('test');
|
||||||
|
assert.throws(() => {
|
||||||
|
structuredClone(e, { transfer: [e] });
|
||||||
|
}, {
|
||||||
|
name: 'DataCloneError',
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user