diff --git a/package-lock.json b/package-lock.json index d59d30e47cc..3cb400b765a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4413,15 +4413,6 @@ "is-arrayish": "0.2.1" } }, - "errorhandler": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.5.0.tgz", - "integrity": "sha1-6rpkyl1UKjEayUX1gt78M2Fl2fQ=", - "requires": { - "accepts": "1.3.4", - "escape-html": "1.0.3" - } - }, "es-abstract": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz", diff --git a/package.json b/package.json index d2a2a1498fa..4c91aca62e7 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,6 @@ "emmet-codemirror": "^1.2.5", "enzyme": "^3.2.0", "enzyme-adapter-react-15": "^1.0.5", - "errorhandler": "^1.4.2", "es6-map": "~0.1.1", "express": "^4.13.3", "express-flash": "~0.0.2", diff --git a/server/middlewares/error-handlers.js b/server/middlewares/error-handlers.js index 5e11a76dfa3..b2c0029341d 100644 --- a/server/middlewares/error-handlers.js +++ b/server/middlewares/error-handlers.js @@ -1,11 +1,47 @@ -import errorHandler from 'errorhandler'; +import { inspect } from 'util'; +import _ from 'lodash/fp'; import accepts from 'accepts'; import { unwrapHandledError } from '../utils/create-handled-error.js'; -export default function prodErrorHandler() { - if (process.env.NODE_ENV === 'development') { - return errorHandler({ log: true }); +const isDev = process.env.NODE_ENV !== 'production'; + +const toString = Object.prototype.toString; +// is full error or just trace +// _.toString(new Error('foo')) => "Error: foo +// Object.prototype.toString.call(new Error('foo')) => "[object Error]" +const isInspect = val => !val.stack && _.toString(val) === toString.call(val); +const stringifyErr = val => { + if (val.stack) { + return String(val.stack); } + + const str = String(val); + + return isInspect(val) ? + inspect(val) : + str; +}; + +const createStackHtml = _.flow( + _.cond([ + [isInspect, err => [err]], + // may be stack or just err.msg + [_.stubTrue, _.flow(stringifyErr, _.split('\n'), _.tail) ] + ]), + _.map(_.escape), + _.map(line => `
  • ${line}`), + _.join('') +); + +const createErrorTitle = _.cond([ + [ + _.negate(isInspect), + _.flow(stringifyErr, _.split('\n'), _.head, _.defaultTo('Error')) + ], + [_.stubTrue, _.constant('Error')] +]); + +export default function prodErrorHandler() { // error handling in production. // disabling eslint due to express parity rules for error handlers return function(err, req, res, next) { // eslint-disable-line @@ -27,7 +63,20 @@ export default function prodErrorHandler() { const redirectTo = handled.redirectTo || '/map'; const message = handled.message || 'Oops! Something went wrong. Please try again later'; + if (type === 'html') { + if (isDev) { + return res.render( + 'dev-error', + { + ...handled, + stack: createStackHtml(err), + errorTitle: createErrorTitle(err), + title: 'freeCodeCamp - Server Error', + status: err.statusCode + } + ); + } if (typeof req.flash === 'function') { req.flash( handled.type || 'errors', diff --git a/server/views/dev-error.jade b/server/views/dev-error.jade new file mode 100644 index 00000000000..fc3d7fd3bed --- /dev/null +++ b/server/views/dev-error.jade @@ -0,0 +1,58 @@ +doctype html +head + title!= errorTitle + style. + * { + margin: 0; + padding: 0; + outline: 0; + } + + body { + padding: 80px 100px; + background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9)); + background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9); + background-repeat: no-repeat; + color: #555; + -webkit-font-smoothing: antialiased; + } + h1, h2 { + font-size: 22px; + color: #343434; + } + h1 em, h2 em { + padding: 0 5px; + font-weight: normal; + } + h1 { + font-size: 60px; + } + h2 { + margin-top: 10px; + } + ul li { + list-style: none; + } + #trace { + margin-top: 10px; + margin-left: 60px; + } +body + #wrapper + h1!= title + h2 + em!= status + | #{errorTitle} + h2 + em User Message: + | #{message} + h2 + em Type: + | #{type} + h2 + em redirect to: + a(href=redirectTo) #{redirectTo} + h2 + em stack trace: + ul#trace!= stack +