Skip to content

Commit 221c8bd

Browse files
TimothyGutargos
authored andcommitted
messaging: use actual DOMException for DataCloneError
PR-URL: #21540 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 3a627c8 commit 221c8bd

File tree

5 files changed

+119
-1
lines changed

5 files changed

+119
-1
lines changed

lib/internal/bootstrap/node.js

+9
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@
101101
setupGlobalURL();
102102
}
103103

104+
if (process.binding('config').experimentalWorker) {
105+
setupDOMException();
106+
}
107+
104108
// On OpenBSD process.execPath will be relative unless we
105109
// get the full path before process.execPath is used.
106110
if (process.platform === 'openbsd') {
@@ -381,6 +385,11 @@
381385
});
382386
}
383387

388+
function setupDOMException() {
389+
// Registers the constructor with C++.
390+
NativeModule.require('internal/domexception');
391+
}
392+
384393
function setupInspector(originalConsole, wrappedConsole, CJSModule) {
385394
if (!process.config.variables.v8_enable_inspector) {
386395
return;

lib/internal/domexception.js

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use strict';
2+
3+
const { internalBinding } = require('internal/bootstrap/loaders');
4+
const { registerDOMException } = internalBinding('messaging');
5+
const { ERR_INVALID_THIS } = require('internal/errors').codes;
6+
7+
const internalsMap = new WeakMap();
8+
9+
const nameToCodeMap = new Map();
10+
11+
class DOMException extends Error {
12+
constructor(message = '', name = 'Error') {
13+
super();
14+
internalsMap.set(this, {
15+
message: `${message}`,
16+
name: `${name}`
17+
});
18+
}
19+
20+
get name() {
21+
const internals = internalsMap.get(this);
22+
if (internals === undefined) {
23+
throw new ERR_INVALID_THIS('DOMException');
24+
}
25+
return internals.name;
26+
}
27+
28+
get message() {
29+
const internals = internalsMap.get(this);
30+
if (internals === undefined) {
31+
throw new ERR_INVALID_THIS('DOMException');
32+
}
33+
return internals.message;
34+
}
35+
36+
get code() {
37+
const internals = internalsMap.get(this);
38+
if (internals === undefined) {
39+
throw new ERR_INVALID_THIS('DOMException');
40+
}
41+
const code = nameToCodeMap.get(internals.name);
42+
return code === undefined ? 0 : code;
43+
}
44+
}
45+
46+
for (const [name, codeName, value] of [
47+
['IndexSizeError', 'INDEX_SIZE_ERR', 1],
48+
['DOMStringSizeError', 'DOMSTRING_SIZE_ERR', 2],
49+
['HierarchyRequestError', 'HIERARCHY_REQUEST_ERR', 3],
50+
['WrongDocumentError', 'WRONG_DOCUMENT_ERR', 4],
51+
['InvalidCharacterError', 'INVALID_CHARACTER_ERR', 5],
52+
['NoDataAllowedError', 'NO_DATA_ALLOWED_ERR', 6],
53+
['NoModificationAllowedError', 'NO_MODIFICATION_ALLOWED_ERR', 7],
54+
['NotFoundError', 'NOT_FOUND_ERR', 8],
55+
['NotSupportedError', 'NOT_SUPPORTED_ERR', 9],
56+
['InUseAttributeError', 'INUSE_ATTRIBUTE_ERR', 10],
57+
['InvalidStateError', 'INVALID_STATE_ERR', 11],
58+
['SyntaxError', 'SYNTAX_ERR', 12],
59+
['InvalidModificationError', 'INVALID_MODIFICATION_ERR', 13],
60+
['NamespaceError', 'NAMESPACE_ERR', 14],
61+
['InvalidAccessError', 'INVALID_ACCESS_ERR', 15],
62+
['ValidationError', 'VALIDATION_ERR', 16],
63+
['TypeMismatchError', 'TYPE_MISMATCH_ERR', 17],
64+
['SecurityError', 'SECURITY_ERR', 18],
65+
['NetworkError', 'NETWORK_ERR', 19],
66+
['AbortError', 'ABORT_ERR', 20],
67+
['URLMismatchError', 'URL_MISMATCH_ERR', 21],
68+
['QuotaExceededError', 'QUOTA_EXCEEDED_ERR', 22],
69+
['TimeoutError', 'TIMEOUT_ERR', 23],
70+
['InvalidNodeTypeError', 'INVALID_NODE_TYPE_ERR', 24],
71+
['DataCloneError', 'DATA_CLONE_ERR', 25]
72+
// There are some more error names, but since they don't have codes assigned,
73+
// we don't need to care about them.
74+
]) {
75+
const desc = { enumerable: true, value };
76+
Object.defineProperty(DOMException, codeName, desc);
77+
Object.defineProperty(DOMException.prototype, codeName, desc);
78+
nameToCodeMap.set(name, value);
79+
}
80+
81+
module.exports = DOMException;
82+
83+
registerDOMException(DOMException);

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
'lib/internal/constants.js',
107107
'lib/internal/dns/promises.js',
108108
'lib/internal/dns/utils.js',
109+
'lib/internal/domexception.js',
109110
'lib/internal/encoding.js',
110111
'lib/internal/errors.js',
111112
'lib/internal/error-serdes.js',

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ struct PackageConfig {
322322
V(buffer_prototype_object, v8::Object) \
323323
V(context, v8::Context) \
324324
V(domain_callback, v8::Function) \
325+
V(domexception_function, v8::Function) \
325326
V(fdclose_constructor_template, v8::ObjectTemplate) \
326327
V(fd_constructor_template, v8::ObjectTemplate) \
327328
V(filehandlereadwrap_template, v8::ObjectTemplate) \

src/node_messaging.cc

+25-1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,21 @@ void Message::AddMessagePort(std::unique_ptr<MessagePortData>&& data) {
144144

145145
namespace {
146146

147+
void ThrowDataCloneError(Environment* env, Local<String> message) {
148+
Local<Value> argv[] = {
149+
message,
150+
FIXED_ONE_BYTE_STRING(env->isolate(), "DataCloneError")
151+
};
152+
Local<Value> exception;
153+
Local<Function> domexception_ctor = env->domexception_function();
154+
CHECK(!domexception_ctor.IsEmpty());
155+
if (!domexception_ctor->NewInstance(env->context(), arraysize(argv), argv)
156+
.ToLocal(&exception)) {
157+
return;
158+
}
159+
env->isolate()->ThrowException(exception);
160+
}
161+
147162
// This tells V8 how to serialize objects that it does not understand
148163
// (e.g. C++ objects) into the output buffer, in a way that our own
149164
// DeserializerDelegate understands how to unpack.
@@ -153,7 +168,7 @@ class SerializerDelegate : public ValueSerializer::Delegate {
153168
: env_(env), context_(context), msg_(m) {}
154169

155170
void ThrowDataCloneError(Local<String> message) override {
156-
env_->isolate()->ThrowException(Exception::Error(message));
171+
ThrowDataCloneError(env_, message);
157172
}
158173

159174
Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object) override {
@@ -688,6 +703,13 @@ static void MessageChannel(const FunctionCallbackInfo<Value>& args) {
688703
.FromJust();
689704
}
690705

706+
static void RegisterDOMException(const FunctionCallbackInfo<Value>& args) {
707+
Environment* env = Environment::GetCurrent(args);
708+
CHECK_EQ(args.Length(), 1);
709+
CHECK(args[0]->IsFunction());
710+
env->set_domexception_function(args[0].As<Function>());
711+
}
712+
691713
static void InitMessaging(Local<Object> target,
692714
Local<Value> unused,
693715
Local<Context> context,
@@ -708,6 +730,8 @@ static void InitMessaging(Local<Object> target,
708730
env->message_port_constructor_string(),
709731
GetMessagePortConstructor(env, context).ToLocalChecked())
710732
.FromJust();
733+
734+
env->SetMethod(target, "registerDOMException", RegisterDOMException);
711735
}
712736

713737
} // anonymous namespace

0 commit comments

Comments
 (0)