You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					290 lines
				
				6.2 KiB
			
		
		
			
		
	
	
					290 lines
				
				6.2 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*!
							 | 
						||
| 
								 | 
							
								 * 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()
							 | 
						||
| 
								 | 
							
								module.exports.isHttpError = createIsHttpErrorFunction(module.exports.HttpError)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// 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]
							 | 
						||
| 
								 | 
							
								    var type = typeof arg
							 | 
						||
| 
								 | 
							
								    if (type === 'object' && arg instanceof Error) {
							 | 
						||
| 
								 | 
							
								      err = arg
							 | 
						||
| 
								 | 
							
								      status = err.status || err.statusCode || status
							 | 
						||
| 
								 | 
							
								    } else if (type === 'number' && i === 0) {
							 | 
						||
| 
								 | 
							
								      status = arg
							 | 
						||
| 
								 | 
							
								    } else if (type === 'string') {
							 | 
						||
| 
								 | 
							
								      msg = arg
							 | 
						||
| 
								 | 
							
								    } else if (type === 'object') {
							 | 
						||
| 
								 | 
							
								      props = arg
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      throw new TypeError('argument #' + (i + 1) + ' unsupported type ' + type)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  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.message[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.message[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 = toClassName(name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function ClientError (message) {
							 | 
						||
| 
								 | 
							
								    // create the error object
							 | 
						||
| 
								 | 
							
								    var msg = message != null ? message : statuses.message[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 function to test is a value is a HttpError.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function createIsHttpErrorFunction (HttpError) {
							 | 
						||
| 
								 | 
							
								  return function isHttpError (val) {
							 | 
						||
| 
								 | 
							
								    if (!val || typeof val !== 'object') {
							 | 
						||
| 
								 | 
							
								      return false
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (val instanceof HttpError) {
							 | 
						||
| 
								 | 
							
								      return true
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return val instanceof Error &&
							 | 
						||
| 
								 | 
							
								      typeof val.expose === 'boolean' &&
							 | 
						||
| 
								 | 
							
								      typeof val.statusCode === 'number' && val.status === val.statusCode
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Create a constructor for a server error.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function createServerErrorConstructor (HttpError, name, code) {
							 | 
						||
| 
								 | 
							
								  var className = toClassName(name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function ServerError (message) {
							 | 
						||
| 
								 | 
							
								    // create the error object
							 | 
						||
| 
								 | 
							
								    var msg = message != null ? message : statuses.message[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.message[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
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Get a class name from a name identifier.
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function toClassName (name) {
							 | 
						||
| 
								 | 
							
								  return name.substr(-5) !== 'Error'
							 | 
						||
| 
								 | 
							
								    ? name + 'Error'
							 | 
						||
| 
								 | 
							
								    : name
							 | 
						||
| 
								 | 
							
								}
							 |