• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const Buffer = require('buffer').Buffer;
4const {
5  ArrayPrototypeForEach,
6  Error,
7  FunctionPrototypeCall,
8  ObjectAssign,
9  ObjectCreate,
10  ObjectDefineProperty,
11  ObjectGetOwnPropertyDescriptor,
12  ObjectGetOwnPropertyNames,
13  ObjectGetPrototypeOf,
14  ObjectKeys,
15  ObjectPrototypeToString,
16  SafeSet,
17  SymbolToStringTag,
18} = primordials;
19
20const kSerializedError = 0;
21const kSerializedObject = 1;
22const kInspectedError = 2;
23
24const errors = {
25  Error, TypeError, RangeError, URIError, SyntaxError, ReferenceError, EvalError
26};
27const errorConstructorNames = new SafeSet(ObjectKeys(errors));
28
29function TryGetAllProperties(object, target = object) {
30  const all = ObjectCreate(null);
31  if (object === null)
32    return all;
33  ObjectAssign(all,
34               TryGetAllProperties(ObjectGetPrototypeOf(object), target));
35  const keys = ObjectGetOwnPropertyNames(object);
36  ArrayPrototypeForEach(keys, (key) => {
37    let descriptor;
38    try {
39      descriptor = ObjectGetOwnPropertyDescriptor(object, key);
40    } catch { return; }
41    const getter = descriptor.get;
42    if (getter && key !== '__proto__') {
43      try {
44        descriptor.value = FunctionPrototypeCall(getter, target);
45      } catch {}
46    }
47    if ('value' in descriptor && typeof descriptor.value !== 'function') {
48      delete descriptor.get;
49      delete descriptor.set;
50      all[key] = descriptor;
51    }
52  });
53  return all;
54}
55
56function GetConstructors(object) {
57  const constructors = [];
58
59  for (let current = object;
60    current !== null;
61    current = ObjectGetPrototypeOf(current)) {
62    const desc = ObjectGetOwnPropertyDescriptor(current, 'constructor');
63    if (desc && desc.value) {
64      ObjectDefineProperty(constructors, constructors.length, {
65        value: desc.value, enumerable: true
66      });
67    }
68  }
69
70  return constructors;
71}
72
73function GetName(object) {
74  const desc = ObjectGetOwnPropertyDescriptor(object, 'name');
75  return desc && desc.value;
76}
77
78let internalUtilInspect;
79function inspect(...args) {
80  if (!internalUtilInspect) {
81    internalUtilInspect = require('internal/util/inspect');
82  }
83  return internalUtilInspect.inspect(...args);
84}
85
86let serialize;
87function serializeError(error) {
88  if (!serialize) serialize = require('v8').serialize;
89  try {
90    if (typeof error === 'object' &&
91        ObjectPrototypeToString(error) === '[object Error]') {
92      const constructors = GetConstructors(error);
93      for (let i = 0; i < constructors.length; i++) {
94        const name = GetName(constructors[i]);
95        if (errorConstructorNames.has(name)) {
96          const serialized = serialize({
97            constructor: name,
98            properties: TryGetAllProperties(error)
99          });
100          return Buffer.concat([Buffer.from([kSerializedError]), serialized]);
101        }
102      }
103    }
104  } catch {}
105  try {
106    const serialized = serialize(error);
107    return Buffer.concat([Buffer.from([kSerializedObject]), serialized]);
108  } catch {}
109  return Buffer.concat([Buffer.from([kInspectedError]),
110                        Buffer.from(inspect(error), 'utf8')]);
111}
112
113let deserialize;
114function deserializeError(error) {
115  if (!deserialize) deserialize = require('v8').deserialize;
116  switch (error[0]) {
117    case kSerializedError:
118      const { constructor, properties } = deserialize(error.subarray(1));
119      const ctor = errors[constructor];
120      ObjectDefineProperty(properties, SymbolToStringTag, {
121        value: { value: 'Error', configurable: true },
122        enumerable: true
123      });
124      return ObjectCreate(ctor.prototype, properties);
125    case kSerializedObject:
126      return deserialize(error.subarray(1));
127    case kInspectedError:
128      const buf = Buffer.from(error.buffer,
129                              error.byteOffset + 1,
130                              error.byteLength - 1);
131      return buf.toString('utf8');
132  }
133  require('assert').fail('This should not happen');
134}
135
136module.exports = { serializeError, deserializeError };
137