2021-12-03 17:58:48 +01:00

169 lines
4.7 KiB
JavaScript

'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;