summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMoshe Atlow <moshe@atlow.co.il>2023-05-12 14:46:32 +0300
committerGitHub <noreply@github.com>2023-05-12 11:46:32 +0000
commit7984af69a090dd6d1f60ffe7e194d5e69bce0c20 (patch)
tree62a8d74d743c798b0a8d98b4db3a9172258b8a33 /lib
parent78123275c2561260368eeebaa84b805830d189f1 (diff)
downloadnode-new-7984af69a090dd6d1f60ffe7e194d5e69bce0c20.tar.gz
worker: support more cases when (de)serializing errors
- error.cause is potentially an error, so is now handled recursively - best effort to serialize thrown symbols - handle thrown object with custom inspect PR-URL: https://github.com/nodejs/node/pull/47925 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/internal/error_serdes.js63
1 files changed, 52 insertions, 11 deletions
diff --git a/lib/internal/error_serdes.js b/lib/internal/error_serdes.js
index 13f3f8b35f..e4850c63aa 100644
--- a/lib/internal/error_serdes.js
+++ b/lib/internal/error_serdes.js
@@ -13,19 +13,31 @@ const {
ObjectGetOwnPropertyNames,
ObjectGetPrototypeOf,
ObjectKeys,
+ ObjectPrototypeHasOwnProperty,
ObjectPrototypeToString,
RangeError,
ReferenceError,
SafeSet,
+ StringFromCharCode,
+ StringPrototypeSubstring,
SymbolToStringTag,
SyntaxError,
+ SymbolFor,
TypeError,
+ TypedArrayPrototypeGetBuffer,
+ TypedArrayPrototypeGetByteOffset,
+ TypedArrayPrototypeGetByteLength,
URIError,
} = primordials;
+const { inspect: { custom: customInspectSymbol } } = require('util');
const kSerializedError = 0;
const kSerializedObject = 1;
const kInspectedError = 2;
+const kInspectedSymbol = 3;
+const kCustomInspectedObject = 4;
+
+const kSymbolStringLength = 'Symbol('.length;
const errors = {
Error, TypeError, RangeError, URIError, SyntaxError, ReferenceError, EvalError,
@@ -42,19 +54,24 @@ function TryGetAllProperties(object, target = object) {
ArrayPrototypeForEach(keys, (key) => {
let descriptor;
try {
+ // TODO: create a null-prototype descriptor with needed properties only
descriptor = ObjectGetOwnPropertyDescriptor(object, key);
} catch { return; }
const getter = descriptor.get;
if (getter && key !== '__proto__') {
try {
descriptor.value = FunctionPrototypeCall(getter, target);
+ delete descriptor.get;
+ delete descriptor.set;
} catch {
// Continue regardless of error.
}
}
- if ('value' in descriptor && typeof descriptor.value !== 'function') {
- delete descriptor.get;
- delete descriptor.set;
+ if (key === 'cause') {
+ descriptor.value = serializeError(descriptor.value);
+ all[key] = descriptor;
+ } else if ('value' in descriptor &&
+ typeof descriptor.value !== 'function' && typeof descriptor.value !== 'symbol') {
all[key] = descriptor;
}
});
@@ -95,6 +112,9 @@ function inspect(...args) {
let serialize;
function serializeError(error) {
if (!serialize) serialize = require('v8').serialize;
+ if (typeof error === 'symbol') {
+ return Buffer.from(StringFromCharCode(kInspectedSymbol) + inspect(error), 'utf8');
+ }
try {
if (typeof error === 'object' &&
ObjectPrototypeToString(error) === '[object Error]') {
@@ -114,13 +134,26 @@ function serializeError(error) {
// Continue regardless of error.
}
try {
+ if (error != null &&
+ ObjectPrototypeHasOwnProperty(error, customInspectSymbol)) {
+ return Buffer.from(StringFromCharCode(kCustomInspectedObject) + inspect(error), 'utf8');
+ }
+ } catch {
+ // Continue regardless of error.
+ }
+ try {
const serialized = serialize(error);
return Buffer.concat([Buffer.from([kSerializedObject]), serialized]);
} catch {
// Continue regardless of error.
}
- return Buffer.concat([Buffer.from([kInspectedError]),
- Buffer.from(inspect(error), 'utf8')]);
+ return Buffer.from(StringFromCharCode(kInspectedError) + inspect(error), 'utf8');
+}
+
+function fromBuffer(error) {
+ return Buffer.from(TypedArrayPrototypeGetBuffer(error),
+ TypedArrayPrototypeGetByteOffset(error) + 1,
+ TypedArrayPrototypeGetByteLength(error) - 1);
}
let deserialize;
@@ -132,19 +165,27 @@ function deserializeError(error) {
const ctor = errors[constructor];
ObjectDefineProperty(properties, SymbolToStringTag, {
__proto__: null,
- value: { value: 'Error', configurable: true },
+ value: { __proto__: null, value: 'Error', configurable: true },
enumerable: true,
});
+ if ('cause' in properties && 'value' in properties.cause) {
+ properties.cause.value = deserializeError(properties.cause.value);
+ }
return ObjectCreate(ctor.prototype, properties);
}
case kSerializedObject:
return deserialize(error.subarray(1));
- case kInspectedError: {
- const buf = Buffer.from(error.buffer,
- error.byteOffset + 1,
- error.byteLength - 1);
- return buf.toString('utf8');
+ case kInspectedError:
+ return fromBuffer(error).toString('utf8');
+ case kInspectedSymbol: {
+ const buf = fromBuffer(error);
+ return SymbolFor(StringPrototypeSubstring(buf.toString('utf8'), kSymbolStringLength, buf.length - 1));
}
+ case kCustomInspectedObject:
+ return {
+ __proto__: null,
+ [customInspectSymbol]: () => fromBuffer(error).toString('utf8'),
+ };
}
require('assert').fail('This should not happen');
}