| // Load modules |
| |
| var Http = require('http'); |
| var Hoek = require('hoek'); |
| |
| |
| // Declare internals |
| |
| var internals = {}; |
| |
| exports.wrap = function (error, statusCode, message) { |
| |
| Hoek.assert(error instanceof Error, 'Cannot wrap non-Error object'); |
| return (error.isBoom ? error : internals.initialize(error, statusCode || 500, message)); |
| }; |
| |
| |
| exports.create = function (statusCode, message, data) { |
| |
| return internals.create(statusCode, message, data, exports.create); |
| }; |
| |
| internals.create = function (statusCode, message, data, ctor) { |
| |
| var error = new Error(message ? message : undefined); // Avoids settings null message |
| Error.captureStackTrace(error, ctor); // Filter the stack to our external API |
| error.data = data || null; |
| internals.initialize(error, statusCode); |
| return error; |
| }; |
| |
| internals.initialize = function (error, statusCode, message) { |
| |
| var numberCode = parseInt(statusCode, 10); |
| Hoek.assert(!isNaN(numberCode) && numberCode >= 400, 'First argument must be a number (400+):', statusCode); |
| |
| error.isBoom = true; |
| error.isServer = numberCode >= 500; |
| |
| if (!error.hasOwnProperty('data')) { |
| error.data = null; |
| } |
| |
| error.output = { |
| statusCode: numberCode, |
| payload: {}, |
| headers: {} |
| }; |
| |
| error.reformat = internals.reformat; |
| error.reformat(); |
| |
| if (!message && |
| !error.message) { |
| |
| message = error.output.payload.error; |
| } |
| |
| if (message) { |
| error.message = (message + (error.message ? ': ' + error.message : '')); |
| } |
| |
| return error; |
| }; |
| |
| |
| internals.reformat = function () { |
| |
| this.output.payload.statusCode = this.output.statusCode; |
| this.output.payload.error = Http.STATUS_CODES[this.output.statusCode] || 'Unknown'; |
| |
| if (this.output.statusCode === 500) { |
| this.output.payload.message = 'An internal server error occurred'; // Hide actual error from user |
| } |
| else if (this.message) { |
| this.output.payload.message = this.message; |
| } |
| }; |
| |
| |
| // 4xx Client Errors |
| |
| exports.badRequest = function (message, data) { |
| |
| return internals.create(400, message, data, exports.badRequest); |
| }; |
| |
| |
| exports.unauthorized = function (message, scheme, attributes) { // Or function (message, wwwAuthenticate[]) |
| |
| var err = internals.create(401, message, undefined, exports.unauthorized); |
| |
| if (!scheme) { |
| return err; |
| } |
| |
| var wwwAuthenticate = ''; |
| var i = 0; |
| var il = 0; |
| |
| if (typeof scheme === 'string') { |
| |
| // function (message, scheme, attributes) |
| |
| wwwAuthenticate = scheme; |
| |
| if (attributes || message) { |
| err.output.payload.attributes = {}; |
| } |
| |
| if (attributes) { |
| var names = Object.keys(attributes); |
| for (i = 0, il = names.length; i < il; ++i) { |
| var name = names[i]; |
| if (i) { |
| wwwAuthenticate += ','; |
| } |
| |
| var value = attributes[name]; |
| if (value === null || |
| value === undefined) { // Value can be zero |
| |
| value = ''; |
| } |
| wwwAuthenticate += ' ' + name + '="' + Hoek.escapeHeaderAttribute(value.toString()) + '"'; |
| err.output.payload.attributes[name] = value; |
| } |
| } |
| |
| if (message) { |
| if (attributes) { |
| wwwAuthenticate += ','; |
| } |
| wwwAuthenticate += ' error="' + Hoek.escapeHeaderAttribute(message) + '"'; |
| err.output.payload.attributes.error = message; |
| } |
| else { |
| err.isMissing = true; |
| } |
| } |
| else { |
| |
| // function (message, wwwAuthenticate[]) |
| |
| var wwwArray = scheme; |
| for (i = 0, il = wwwArray.length; i < il; ++i) { |
| if (i) { |
| wwwAuthenticate += ', '; |
| } |
| |
| wwwAuthenticate += wwwArray[i]; |
| } |
| } |
| |
| err.output.headers['WWW-Authenticate'] = wwwAuthenticate; |
| |
| return err; |
| }; |
| |
| |
| exports.forbidden = function (message, data) { |
| |
| return internals.create(403, message, data, exports.forbidden); |
| }; |
| |
| |
| exports.notFound = function (message, data) { |
| |
| return internals.create(404, message, data, exports.notFound); |
| }; |
| |
| |
| exports.methodNotAllowed = function (message, data) { |
| |
| return internals.create(405, message, data, exports.methodNotAllowed); |
| }; |
| |
| |
| exports.notAcceptable = function (message, data) { |
| |
| return internals.create(406, message, data, exports.notAcceptable); |
| }; |
| |
| |
| exports.proxyAuthRequired = function (message, data) { |
| |
| return internals.create(407, message, data, exports.proxyAuthRequired); |
| }; |
| |
| |
| exports.clientTimeout = function (message, data) { |
| |
| return internals.create(408, message, data, exports.clientTimeout); |
| }; |
| |
| |
| exports.conflict = function (message, data) { |
| |
| return internals.create(409, message, data, exports.conflict); |
| }; |
| |
| |
| exports.resourceGone = function (message, data) { |
| |
| return internals.create(410, message, data, exports.resourceGone); |
| }; |
| |
| |
| exports.lengthRequired = function (message, data) { |
| |
| return internals.create(411, message, data, exports.lengthRequired); |
| }; |
| |
| |
| exports.preconditionFailed = function (message, data) { |
| |
| return internals.create(412, message, data, exports.preconditionFailed); |
| }; |
| |
| |
| exports.entityTooLarge = function (message, data) { |
| |
| return internals.create(413, message, data, exports.entityTooLarge); |
| }; |
| |
| |
| exports.uriTooLong = function (message, data) { |
| |
| return internals.create(414, message, data, exports.uriTooLong); |
| }; |
| |
| |
| exports.unsupportedMediaType = function (message, data) { |
| |
| return internals.create(415, message, data, exports.unsupportedMediaType); |
| }; |
| |
| |
| exports.rangeNotSatisfiable = function (message, data) { |
| |
| return internals.create(416, message, data, exports.rangeNotSatisfiable); |
| }; |
| |
| |
| exports.expectationFailed = function (message, data) { |
| |
| return internals.create(417, message, data, exports.expectationFailed); |
| }; |
| |
| exports.badData = function (message, data) { |
| |
| return internals.create(422, message, data, exports.badData); |
| }; |
| |
| |
| exports.preconditionRequired = function (message, data) { |
| |
| return internals.create(428, message, data, exports.preconditionRequired); |
| }; |
| |
| |
| exports.tooManyRequests = function (message, data) { |
| |
| return internals.create(429, message, data, exports.tooManyRequests); |
| }; |
| |
| |
| // 5xx Server Errors |
| |
| exports.internal = function (message, data, statusCode) { |
| |
| return internals.serverError(message, data, statusCode, exports.internal); |
| }; |
| |
| internals.serverError = function (message, data, statusCode, ctor) { |
| |
| var error; |
| if (data instanceof Error) { |
| error = exports.wrap(data, statusCode, message); |
| } else { |
| error = internals.create(statusCode || 500, message, undefined, ctor); |
| error.data = data; |
| } |
| |
| return error; |
| }; |
| |
| |
| exports.notImplemented = function (message, data) { |
| |
| return internals.serverError(message, data, 501, exports.notImplemented); |
| }; |
| |
| |
| exports.badGateway = function (message, data) { |
| |
| return internals.serverError(message, data, 502, exports.badGateway); |
| }; |
| |
| |
| exports.serverTimeout = function (message, data) { |
| |
| return internals.serverError(message, data, 503, exports.serverTimeout); |
| }; |
| |
| |
| exports.gatewayTimeout = function (message, data) { |
| |
| return internals.serverError(message, data, 504, exports.gatewayTimeout); |
| }; |
| |
| |
| exports.badImplementation = function (message, data) { |
| |
| var err = internals.serverError(message, data, 500, exports.badImplementation); |
| err.isDeveloperError = true; |
| return err; |
| }; |