/lib/handlers/error.js
JavaScript | 132 lines | 100 code | 21 blank | 11 comment | 25 complexity | e1e47eb3cc80ecd2cc71204437879b89 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause
- var utils = require('../utils'),
- errors = require('../errors'),
- BinHandler = require('./bin'),
- Observable = utils.Observable,
- crypto = require('crypto');
- // Handles application errors.
- module.exports = Observable.extend({
- constructor: function ErrorHandler(sandbox) {
- Observable.apply(this, arguments);
- this.sandbox = sandbox;
- this.helpers = sandbox.helpers;
- this.mailer = sandbox.mailer;
- utils.bindAll(this, 'notFound', 'httpError', 'uncaughtError');
- },
- // Handles all types of HTTPError and ensures that the correct type of
- // response is returned depending on the type of content requested. So if
- // you're expecting JSON you should get JSON.
- httpError: function (err, req, res, next) {
- err = this.coerceError(err);
- if (err instanceof errors.NotFound && req.accepts('html')) {
- if (err instanceof errors.BinNotFound) {
- return (new BinHandler(this.sandbox)).notFound(req, res);
- } else {
- return this.renderErrorPage(err, req, res);
- }
- } else if (err instanceof errors.HTTPError) {
- return this.renderError(err, req, res);
- }
- next(err);
- },
- // Fall through handler for when no routes match.
- notFound: function (req, res, next) {
- var error = new errors.NotFound('Page Does Not Exist');
- if (req.accepts('html')) {
- this.renderErrorPage(error, req, res);
- } else {
- this.renderError(error, req, res);
- }
- },
- // Displays a friendly 500 page in production if requesting html otherwise
- // returns an appropriate format.
- uncaughtError: function (err, req, res, next) {
- this.sendErrorReport(err, req);
- if (req.accepts('html')) {
- this.renderErrorPage(err, req, res);
- } else {
- var error = new errors.HTTPError(500, 'Internal Server Error');
- this.renderError(error, req, res);
- }
- },
- renderError: function (err, req, res) {
- res.status(err.status);
- if (req.accepts(['html'])) {
- res.contentType('html');
- res.send(err.toHTMLString());
- } else if (req.accepts(['json'])) {
- res.json(err);
- } else {
- res.contentType('txt');
- res.send(err.toString());
- }
- },
- renderErrorPage: function (err, req, res) {
- var status = err.status || 500;
- res.status(status).render('error', {
- is_500: status !== 404, // Saves us having many error pages at the mo.
- is_404: status === 404,
- root: this.helpers.url('', true),
- dave: this.helpers.urlForStatic('/images/logo.png')
- });
- },
- sendErrorReport: function (err, req) {
- var to = this.helpers.set('notify errors'),
- session = utils.extend({}, req.session),
- context, headers;
- if (this.helpers.production && to && to.length) {
- // Don't send the users email address via email.
- if (session && session.user) {
- delete session.user.email;
- }
- headers = utils.extend({}, req.headers);
- delete headers.cookie;
- context = {
- name: err.name,
- message: err.message,
- hash: crypto.createHash('md5').update(err.stack).digest('hex').slice(0, 6),
- stack: err.stack,
- body: JSON.stringify(req.body, null, 2),
- session: JSON.stringify(session, null, 2) || null,
- url: this.helpers.url(req.url, true),
- path: req.url,
- headers: JSON.stringify(headers, null, 2) || null,
- method: req.method
- };
- if (context.body === '{}') {
- context.body = null;
- }
- this.mailer.errorReport(to, context);
- }
- },
- // Checks to see if the error has a status property and if so converts
- // it into an instance of HTTPError. Just returns this original error
- // if no status is found.
- coerceError: function (err) {
- var status = typeof err === 'number' ? err : err.status;
- if (!(err instanceof errors.HTTPError) && status) {
- return errors.create(status, err.message);
- }
- return err;
- }
- });