| /*! |
| * http-errors |
| * Copyright(c) 2014 Jonathan Ong |
| * Copyright(c) 2016 Douglas Christopher Wilson |
| * MIT Licensed |
| */ |
| |
| 'use strict' |
| |
| /** |
| * Module dependencies. |
| * @private |
| */ |
| |
| var deprecate = require('depd')('http-errors') |
| var setPrototypeOf = require('setprototypeof') |
| var statuses = require('statuses') |
| var inherits = require('inherits') |
| var toIdentifier = require('toidentifier') |
| |
| /** |
| * Module exports. |
| * @public |
| */ |
| |
| module.exports = createError |
| module.exports.HttpError = createHttpErrorConstructor() |
| |
| // Populate exports for all constructors |
| populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError) |
| |
| /** |
| * Get the code class of a status code. |
| * @private |
| */ |
| |
| function codeClass (status) { |
| return Number(String(status).charAt(0) + '00') |
| } |
| |
| /** |
| * Create a new HTTP Error. |
| * |
| * @returns {Error} |
| * @public |
| */ |
| |
| function createError () { |
| // so much arity going on ~_~ |
| var err |
| var msg |
| var status = 500 |
| var props = {} |
| for (var i = 0; i < arguments.length; i++) { |
| var arg = arguments[i] |
| if (arg instanceof Error) { |
| err = arg |
| status = err.status || err.statusCode || status |
| continue |
| } |
| switch (typeof arg) { |
| case 'string': |
| msg = arg |
| break |
| case 'number': |
| status = arg |
| if (i !== 0) { |
| deprecate('non-first-argument status code; replace with createError(' + arg + ', ...)') |
| } |
| break |
| case 'object': |
| props = arg |
| break |
| } |
| } |
| |
| if (typeof status === 'number' && (status < 400 || status >= 600)) { |
| deprecate('non-error status code; use only 4xx or 5xx status codes') |
| } |
| |
| if (typeof status !== 'number' || |
| (!statuses[status] && (status < 400 || status >= 600))) { |
| status = 500 |
| } |
| |
| // constructor |
| var HttpError = createError[status] || createError[codeClass(status)] |
| |
| if (!err) { |
| // create error |
| err = HttpError |
| ? new HttpError(msg) |
| : new Error(msg || statuses[status]) |
| Error.captureStackTrace(err, createError) |
| } |
| |
| if (!HttpError || !(err instanceof HttpError) || err.status !== status) { |
| // add properties to generic error |
| err.expose = status < 500 |
| err.status = err.statusCode = status |
| } |
| |
| for (var key in props) { |
| if (key !== 'status' && key !== 'statusCode') { |
| err[key] = props[key] |
| } |
| } |
| |
| return err |
| } |
| |
| /** |
| * Create HTTP error abstract base class. |
| * @private |
| */ |
| |
| function createHttpErrorConstructor () { |
| function HttpError () { |
| throw new TypeError('cannot construct abstract class') |
| } |
| |
| inherits(HttpError, Error) |
| |
| return HttpError |
| } |
| |
| /** |
| * Create a constructor for a client error. |
| * @private |
| */ |
| |
| function createClientErrorConstructor (HttpError, name, code) { |
| var className = name.match(/Error$/) ? name : name + 'Error' |
| |
| function ClientError (message) { |
| // create the error object |
| var msg = message != null ? message : statuses[code] |
| var err = new Error(msg) |
| |
| // capture a stack trace to the construction point |
| Error.captureStackTrace(err, ClientError) |
| |
| // adjust the [[Prototype]] |
| setPrototypeOf(err, ClientError.prototype) |
| |
| // redefine the error message |
| Object.defineProperty(err, 'message', { |
| enumerable: true, |
| configurable: true, |
| value: msg, |
| writable: true |
| }) |
| |
| // redefine the error name |
| Object.defineProperty(err, 'name', { |
| enumerable: false, |
| configurable: true, |
| value: className, |
| writable: true |
| }) |
| |
| return err |
| } |
| |
| inherits(ClientError, HttpError) |
| nameFunc(ClientError, className) |
| |
| ClientError.prototype.status = code |
| ClientError.prototype.statusCode = code |
| ClientError.prototype.expose = true |
| |
| return ClientError |
| } |
| |
| /** |
| * Create a constructor for a server error. |
| * @private |
| */ |
| |
| function createServerErrorConstructor (HttpError, name, code) { |
| var className = name.match(/Error$/) ? name : name + 'Error' |
| |
| function ServerError (message) { |
| // create the error object |
| var msg = message != null ? message : statuses[code] |
| var err = new Error(msg) |
| |
| // capture a stack trace to the construction point |
| Error.captureStackTrace(err, ServerError) |
| |
| // adjust the [[Prototype]] |
| setPrototypeOf(err, ServerError.prototype) |
| |
| // redefine the error message |
| Object.defineProperty(err, 'message', { |
| enumerable: true, |
| configurable: true, |
| value: msg, |
| writable: true |
| }) |
| |
| // redefine the error name |
| Object.defineProperty(err, 'name', { |
| enumerable: false, |
| configurable: true, |
| value: className, |
| writable: true |
| }) |
| |
| return err |
| } |
| |
| inherits(ServerError, HttpError) |
| nameFunc(ServerError, className) |
| |
| ServerError.prototype.status = code |
| ServerError.prototype.statusCode = code |
| ServerError.prototype.expose = false |
| |
| return ServerError |
| } |
| |
| /** |
| * Set the name of a function, if possible. |
| * @private |
| */ |
| |
| function nameFunc (func, name) { |
| var desc = Object.getOwnPropertyDescriptor(func, 'name') |
| |
| if (desc && desc.configurable) { |
| desc.value = name |
| Object.defineProperty(func, 'name', desc) |
| } |
| } |
| |
| /** |
| * Populate the exports object with constructors for every error class. |
| * @private |
| */ |
| |
| function populateConstructorExports (exports, codes, HttpError) { |
| codes.forEach(function forEachCode (code) { |
| var CodeError |
| var name = toIdentifier(statuses[code]) |
| |
| switch (codeClass(code)) { |
| case 400: |
| CodeError = createClientErrorConstructor(HttpError, name, code) |
| break |
| case 500: |
| CodeError = createServerErrorConstructor(HttpError, name, code) |
| break |
| } |
| |
| if (CodeError) { |
| // export the constructor |
| exports[code] = CodeError |
| exports[name] = CodeError |
| } |
| }) |
| |
| // backwards-compatibility |
| exports["I'mateapot"] = deprecate.function(exports.ImATeapot, |
| '"I\'mateapot"; use "ImATeapot" instead') |
| } |