messaging: use actual DOMException for DataCloneError

PR-URL: https://github.com/nodejs/node/pull/21540
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Timothy Gu 2018-06-25 00:48:48 -04:00
parent 602da6492f
commit 5f3bdb016a
No known key found for this signature in database
GPG Key ID: 7FE6B095B582B0D4
5 changed files with 119 additions and 1 deletions

View File

@ -125,6 +125,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') {
@ -405,6 +409,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;

View File

@ -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);

View File

@ -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',

View File

@ -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) \

View File

@ -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.
@ -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 {
@ -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,
@ -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