Projekt

Obecné

Profil

Stáhnout (5.74 KB) Statistiky
| Větev: | Revize:
1
/*!
2
 * http-errors
3
 * Copyright(c) 2014 Jonathan Ong
4
 * Copyright(c) 2016 Douglas Christopher Wilson
5
 * MIT Licensed
6
 */
7

    
8
'use strict'
9

    
10
/**
11
 * Module dependencies.
12
 * @private
13
 */
14

    
15
var deprecate = require('depd')('http-errors')
16
var setPrototypeOf = require('setprototypeof')
17
var statuses = require('statuses')
18
var inherits = require('inherits')
19
var toIdentifier = require('toidentifier')
20

    
21
/**
22
 * Module exports.
23
 * @public
24
 */
25

    
26
module.exports = createError
27
module.exports.HttpError = createHttpErrorConstructor()
28

    
29
// Populate exports for all constructors
30
populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError)
31

    
32
/**
33
 * Get the code class of a status code.
34
 * @private
35
 */
36

    
37
function codeClass (status) {
38
  return Number(String(status).charAt(0) + '00')
39
}
40

    
41
/**
42
 * Create a new HTTP Error.
43
 *
44
 * @returns {Error}
45
 * @public
46
 */
47

    
48
function createError () {
49
  // so much arity going on ~_~
50
  var err
51
  var msg
52
  var status = 500
53
  var props = {}
54
  for (var i = 0; i < arguments.length; i++) {
55
    var arg = arguments[i]
56
    if (arg instanceof Error) {
57
      err = arg
58
      status = err.status || err.statusCode || status
59
      continue
60
    }
61
    switch (typeof arg) {
62
      case 'string':
63
        msg = arg
64
        break
65
      case 'number':
66
        status = arg
67
        if (i !== 0) {
68
          deprecate('non-first-argument status code; replace with createError(' + arg + ', ...)')
69
        }
70
        break
71
      case 'object':
72
        props = arg
73
        break
74
    }
75
  }
76

    
77
  if (typeof status === 'number' && (status < 400 || status >= 600)) {
78
    deprecate('non-error status code; use only 4xx or 5xx status codes')
79
  }
80

    
81
  if (typeof status !== 'number' ||
82
    (!statuses[status] && (status < 400 || status >= 600))) {
83
    status = 500
84
  }
85

    
86
  // constructor
87
  var HttpError = createError[status] || createError[codeClass(status)]
88

    
89
  if (!err) {
90
    // create error
91
    err = HttpError
92
      ? new HttpError(msg)
93
      : new Error(msg || statuses[status])
94
    Error.captureStackTrace(err, createError)
95
  }
96

    
97
  if (!HttpError || !(err instanceof HttpError) || err.status !== status) {
98
    // add properties to generic error
99
    err.expose = status < 500
100
    err.status = err.statusCode = status
101
  }
102

    
103
  for (var key in props) {
104
    if (key !== 'status' && key !== 'statusCode') {
105
      err[key] = props[key]
106
    }
107
  }
108

    
109
  return err
110
}
111

    
112
/**
113
 * Create HTTP error abstract base class.
114
 * @private
115
 */
116

    
117
function createHttpErrorConstructor () {
118
  function HttpError () {
119
    throw new TypeError('cannot construct abstract class')
120
  }
121

    
122
  inherits(HttpError, Error)
123

    
124
  return HttpError
125
}
126

    
127
/**
128
 * Create a constructor for a client error.
129
 * @private
130
 */
131

    
132
function createClientErrorConstructor (HttpError, name, code) {
133
  var className = name.match(/Error$/) ? name : name + 'Error'
134

    
135
  function ClientError (message) {
136
    // create the error object
137
    var msg = message != null ? message : statuses[code]
138
    var err = new Error(msg)
139

    
140
    // capture a stack trace to the construction point
141
    Error.captureStackTrace(err, ClientError)
142

    
143
    // adjust the [[Prototype]]
144
    setPrototypeOf(err, ClientError.prototype)
145

    
146
    // redefine the error message
147
    Object.defineProperty(err, 'message', {
148
      enumerable: true,
149
      configurable: true,
150
      value: msg,
151
      writable: true
152
    })
153

    
154
    // redefine the error name
155
    Object.defineProperty(err, 'name', {
156
      enumerable: false,
157
      configurable: true,
158
      value: className,
159
      writable: true
160
    })
161

    
162
    return err
163
  }
164

    
165
  inherits(ClientError, HttpError)
166
  nameFunc(ClientError, className)
167

    
168
  ClientError.prototype.status = code
169
  ClientError.prototype.statusCode = code
170
  ClientError.prototype.expose = true
171

    
172
  return ClientError
173
}
174

    
175
/**
176
 * Create a constructor for a server error.
177
 * @private
178
 */
179

    
180
function createServerErrorConstructor (HttpError, name, code) {
181
  var className = name.match(/Error$/) ? name : name + 'Error'
182

    
183
  function ServerError (message) {
184
    // create the error object
185
    var msg = message != null ? message : statuses[code]
186
    var err = new Error(msg)
187

    
188
    // capture a stack trace to the construction point
189
    Error.captureStackTrace(err, ServerError)
190

    
191
    // adjust the [[Prototype]]
192
    setPrototypeOf(err, ServerError.prototype)
193

    
194
    // redefine the error message
195
    Object.defineProperty(err, 'message', {
196
      enumerable: true,
197
      configurable: true,
198
      value: msg,
199
      writable: true
200
    })
201

    
202
    // redefine the error name
203
    Object.defineProperty(err, 'name', {
204
      enumerable: false,
205
      configurable: true,
206
      value: className,
207
      writable: true
208
    })
209

    
210
    return err
211
  }
212

    
213
  inherits(ServerError, HttpError)
214
  nameFunc(ServerError, className)
215

    
216
  ServerError.prototype.status = code
217
  ServerError.prototype.statusCode = code
218
  ServerError.prototype.expose = false
219

    
220
  return ServerError
221
}
222

    
223
/**
224
 * Set the name of a function, if possible.
225
 * @private
226
 */
227

    
228
function nameFunc (func, name) {
229
  var desc = Object.getOwnPropertyDescriptor(func, 'name')
230

    
231
  if (desc && desc.configurable) {
232
    desc.value = name
233
    Object.defineProperty(func, 'name', desc)
234
  }
235
}
236

    
237
/**
238
 * Populate the exports object with constructors for every error class.
239
 * @private
240
 */
241

    
242
function populateConstructorExports (exports, codes, HttpError) {
243
  codes.forEach(function forEachCode (code) {
244
    var CodeError
245
    var name = toIdentifier(statuses[code])
246

    
247
    switch (codeClass(code)) {
248
      case 400:
249
        CodeError = createClientErrorConstructor(HttpError, name, code)
250
        break
251
      case 500:
252
        CodeError = createServerErrorConstructor(HttpError, name, code)
253
        break
254
    }
255

    
256
    if (CodeError) {
257
      // export the constructor
258
      exports[code] = CodeError
259
      exports[name] = CodeError
260
    }
261
  })
262

    
263
  // backwards-compatibility
264
  exports["I'mateapot"] = deprecate.function(exports.ImATeapot,
265
    '"I\'mateapot"; use "ImATeapot" instead')
266
}
(4-4/5)