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