wzp
2021-05-13 7d694a9113118daec5be7ac224dab46a3b20f106
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
'use strict';
 
// core modules
var util = require('util');
 
// external modules
var assert = require('assert-plus');
var nerror = require('@netflix/nerror');
 
// internal files
var helpers = require('./../helpers');
 
var WError = nerror.WError;
 
 
/**
 * Base HttpError class. inherits from WError.
 * Variadic signature, first two are special to Restify, using a options obj.
 * 1) new HttpError(anotherErr, {...});
 * 2) new HttpError({...});
 * Last one is a straight pass through to WError
 * 3) new HttpError('my special error message');
 * @public
 * @class
 */
function HttpError() {
 
    var self = this;
    var parsed = helpers.parseVErrorArgs(arguments);
    var verrorArgs = (parsed.verrorArgs.length !== 0) ?
        parsed.verrorArgs :
        [ self.message ];
    var opts = parsed.internalOpts;
 
    // if we have opts for use with restify-error's constructors, assert on them
    // now.
    assert.optionalNumber(opts.statusCode, 'opts.statusCode');
    assert.optionalFunc(opts.toJSON, 'opts.toJSON');
    assert.optionalFunc(opts.toString, 'opts.toString');
 
    // inherit from WError, call super first before doing anything else!  WError
    // will handle calling captureStackTrace, using arguments.callee to
    // eliminate unnecessary stack frames.
    WError.apply(self, verrorArgs);
 
    /**
     * the http status code of the error.
     * because inherited classes have status code set on the prototype,
     * only assign a status code if truthy.
     * @property
     * @type {Number}
     */
    if (opts.statusCode) {
        self.statusCode = opts.statusCode;
    }
 
    /**
     * property used to describe the error. emulates some of the core module
     * errors that have codes on them to describe their nature,
     * i.e., fs.readFile can return an ENOENT error where err.code is 'ENOENT'
     * @property
     * @type {String}
     */
    if (opts.code) {
        self.code = opts.code;
    }
 
    /**
     * an object used to render the error when serialized (JSON.stringify or
     * toString)
     * @property
     * @type {Object}
     */
    self.body = {
        // err.code/err.restCode is used by legacy restify paths, probably
        // originally created to emulate the code property that is created by
        // some native core module errors (i.e., a failed fs.readFile will
        // return a ENOENT error with a err.code of ENOENT).
        //
        // for Http/RestErrors, the code will be the error name but with
        // 'error' truncated from the string. i.e., if the error name is
        // InternalServerError, the code is InternalServer.
        code: opts.code || self.code,
        message: self.message || ''
    };
 
    /**
     * override prototype toJSON method. must use 'hasOwnProperty' to ensure we
     * are picking up a user specified option vs the one set on object literals.
     * @property
     * @type {Function}
     */
    if (opts.hasOwnProperty('toJSON')) {
        self.toJSON = opts.toJSON;
    }
 
    /**
     * override prototype toJSON method. must use 'hasOwnProperty' to ensure we
     * are picking up a user specified option vs the one set on object literals.
     * @property
     * @type {Function}
     */
    if (opts.hasOwnProperty('toString')) {
        self.toString = opts.toString;
    }
}
util.inherits(HttpError, WError);
 
/**
 * migration method to allow continued use of `.context` property that has now
 * been migrated to use VError's info object under the hood.
 * @type {Object}
 */
Object.defineProperty(HttpError.prototype, 'context', {
    get: function getContext() {
        var self = this;
        return nerror.info(self);
    }
});
 
/**
 * assign non-standard display name property on the CONSTRUCTOR (not prototype),
 * which is supported by all VMs. useful for stack trace output.
 * @type {String}
 */
HttpError.displayName = 'HttpError';
 
/**
 * the name of the error, used in the stack trace output
 * @type {String}
 */
HttpError.prototype.name = 'HttpError';
 
/**
 * the default error code
 * @type {String}
 */
HttpError.prototype.code = 'Error';
 
 
/**
 * implement a basic toString/JSON.stringify. they should be identical.
 * @public
 * @method toJSON
 * @returns {String}
 */
HttpError.prototype.toJSON = function toJSON() {
    var self = this;
    var message = '';
 
    // if we have a cause, get the full VError toString() without the current
    // error name. verbose check, self.cause can exist but returns undefined
    if (self.cause && typeof self.cause === 'function' && self.cause()) {
        var fullString = self.toString();
        message = fullString.substr(fullString.indexOf(' ') + 1);
    } else {
        message = self.body.message;
    }
 
    return {
        code: self.body.code,
        message: message
    };
};
 
 
 
module.exports = HttpError;