Skip to content

Commit

Permalink
messaging: use actual DOMException for DataCloneError
Browse files Browse the repository at this point in the history
PR-URL: #21540
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
TimothyGu authored and targos committed Jul 4, 2018
1 parent 3a627c8 commit 221c8bd
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 1 deletion.
9 changes: 9 additions & 0 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@
setupGlobalURL();
}

if (process.binding('config').experimentalWorker) {
setupDOMException();
}

// On OpenBSD process.execPath will be relative unless we
// get the full path before process.execPath is used.
if (process.platform === 'openbsd') {
Expand Down Expand Up @@ -381,6 +385,11 @@
});
}

function setupDOMException() {
// Registers the constructor with C++.
NativeModule.require('internal/domexception');
}

function setupInspector(originalConsole, wrappedConsole, CJSModule) {
if (!process.config.variables.v8_enable_inspector) {
return;
Expand Down
83 changes: 83 additions & 0 deletions lib/internal/domexception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';

const { internalBinding } = require('internal/bootstrap/loaders');
const { registerDOMException } = internalBinding('messaging');
const { ERR_INVALID_THIS } = require('internal/errors').codes;

const internalsMap = new WeakMap();

const nameToCodeMap = new Map();

class DOMException extends Error {
constructor(message = '', name = 'Error') {
super();
internalsMap.set(this, {
message: `${message}`,
name: `${name}`
});
}

get name() {
const internals = internalsMap.get(this);
if (internals === undefined) {
throw new ERR_INVALID_THIS('DOMException');
}
return internals.name;
}

get message() {
const internals = internalsMap.get(this);
if (internals === undefined) {
throw new ERR_INVALID_THIS('DOMException');
}
return internals.message;
}

get code() {
const internals = internalsMap.get(this);
if (internals === undefined) {
throw new ERR_INVALID_THIS('DOMException');
}
const code = nameToCodeMap.get(internals.name);
return code === undefined ? 0 : code;
}
}

for (const [name, codeName, value] of [
['IndexSizeError', 'INDEX_SIZE_ERR', 1],
['DOMStringSizeError', 'DOMSTRING_SIZE_ERR', 2],
['HierarchyRequestError', 'HIERARCHY_REQUEST_ERR', 3],
['WrongDocumentError', 'WRONG_DOCUMENT_ERR', 4],
['InvalidCharacterError', 'INVALID_CHARACTER_ERR', 5],
['NoDataAllowedError', 'NO_DATA_ALLOWED_ERR', 6],
['NoModificationAllowedError', 'NO_MODIFICATION_ALLOWED_ERR', 7],
['NotFoundError', 'NOT_FOUND_ERR', 8],
['NotSupportedError', 'NOT_SUPPORTED_ERR', 9],
['InUseAttributeError', 'INUSE_ATTRIBUTE_ERR', 10],
['InvalidStateError', 'INVALID_STATE_ERR', 11],
['SyntaxError', 'SYNTAX_ERR', 12],
['InvalidModificationError', 'INVALID_MODIFICATION_ERR', 13],
['NamespaceError', 'NAMESPACE_ERR', 14],
['InvalidAccessError', 'INVALID_ACCESS_ERR', 15],
['ValidationError', 'VALIDATION_ERR', 16],
['TypeMismatchError', 'TYPE_MISMATCH_ERR', 17],
['SecurityError', 'SECURITY_ERR', 18],
['NetworkError', 'NETWORK_ERR', 19],
['AbortError', 'ABORT_ERR', 20],
['URLMismatchError', 'URL_MISMATCH_ERR', 21],
['QuotaExceededError', 'QUOTA_EXCEEDED_ERR', 22],
['TimeoutError', 'TIMEOUT_ERR', 23],
['InvalidNodeTypeError', 'INVALID_NODE_TYPE_ERR', 24],
['DataCloneError', 'DATA_CLONE_ERR', 25]
// There are some more error names, but since they don't have codes assigned,
// we don't need to care about them.
]) {
const desc = { enumerable: true, value };
Object.defineProperty(DOMException, codeName, desc);
Object.defineProperty(DOMException.prototype, codeName, desc);
nameToCodeMap.set(name, value);
}

module.exports = DOMException;

registerDOMException(DOMException);
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
'lib/internal/constants.js',
'lib/internal/dns/promises.js',
'lib/internal/dns/utils.js',
'lib/internal/domexception.js',
'lib/internal/encoding.js',
'lib/internal/errors.js',
'lib/internal/error-serdes.js',
Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ struct PackageConfig {
V(buffer_prototype_object, v8::Object) \
V(context, v8::Context) \
V(domain_callback, v8::Function) \
V(domexception_function, v8::Function) \
V(fdclose_constructor_template, v8::ObjectTemplate) \
V(fd_constructor_template, v8::ObjectTemplate) \
V(filehandlereadwrap_template, v8::ObjectTemplate) \
Expand Down
26 changes: 25 additions & 1 deletion src/node_messaging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ void Message::AddMessagePort(std::unique_ptr<MessagePortData>&& data) {

namespace {

void ThrowDataCloneError(Environment* env, Local<String> message) {
Local<Value> argv[] = {
message,
FIXED_ONE_BYTE_STRING(env->isolate(), "DataCloneError")
};
Local<Value> exception;
Local<Function> domexception_ctor = env->domexception_function();
CHECK(!domexception_ctor.IsEmpty());
if (!domexception_ctor->NewInstance(env->context(), arraysize(argv), argv)
.ToLocal(&exception)) {
return;
}
env->isolate()->ThrowException(exception);
}

// This tells V8 how to serialize objects that it does not understand
// (e.g. C++ objects) into the output buffer, in a way that our own
// DeserializerDelegate understands how to unpack.
Expand All @@ -153,7 +168,7 @@ class SerializerDelegate : public ValueSerializer::Delegate {
: env_(env), context_(context), msg_(m) {}

void ThrowDataCloneError(Local<String> message) override {
env_->isolate()->ThrowException(Exception::Error(message));
ThrowDataCloneError(env_, message);
}

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

static void RegisterDOMException(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
CHECK_EQ(args.Length(), 1);
CHECK(args[0]->IsFunction());
env->set_domexception_function(args[0].As<Function>());
}

static void InitMessaging(Local<Object> target,
Local<Value> unused,
Local<Context> context,
Expand All @@ -708,6 +730,8 @@ static void InitMessaging(Local<Object> target,
env->message_port_constructor_string(),
GetMessagePortConstructor(env, context).ToLocalChecked())
.FromJust();

env->SetMethod(target, "registerDOMException", RegisterDOMException);
}

} // anonymous namespace
Expand Down

0 comments on commit 221c8bd

Please sign in to comment.