diff --git a/HISTORY.md b/HISTORY.md index 5b3acbf..8a07998 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,8 @@ +unreleased +========== + + * Fix heading content to not include stack + 1.3.1 / 2014-12-31 ================== @@ -10,6 +15,11 @@ * Add `log` option +1.2.4 / 2015-01-01 +================== + + * Fix heading content to not include stack + 1.2.3 / 2014-11-21 ================== diff --git a/LICENSE b/LICENSE index f23dca8..386b7b6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ (The MIT License) Copyright (c) 2014 Jonathan Ong +Copyright (c) 2014-2015 Douglas Christopher Wilson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/index.js b/index.js index 652c13b..4d8b372 100644 --- a/index.js +++ b/index.js @@ -3,7 +3,7 @@ * Copyright(c) 2010 Sencha Inc. * Copyright(c) 2011 TJ Holowaychuk * Copyright(c) 2014 Jonathan Ong - * Copyright(c) 2014 Douglas Christopher Wilson + * Copyright(c) 2014-2015 Douglas Christopher Wilson * MIT Licensed */ @@ -22,7 +22,9 @@ var util = require('util') * @private */ +var doubleSpaceGlobalRegExp = / /g var inspect = util.inspect +var newLineGlobalRegExp = /\n/g var toString = Object.prototype.toString /* istanbul ignore next */ @@ -111,17 +113,24 @@ exports = module.exports = function errorHandler(options) { if (e) return next(e); fs.readFile(__dirname + '/public/error.html', 'utf8', function(e, html){ if (e) return next(e); - var stack = String(err.stack || '') - .split('\n').slice(1) - .map(function(v){ return '
  • ' + escapeHtml(v).replace(/ /g, '  ') + '
  • '; }).join(''); - html = html - .replace('{style}', style) - .replace('{stack}', stack) - .replace('{title}', escapeHtml(exports.title)) - .replace('{statusCode}', res.statusCode) - .replace(/\{error\}/g, escapeHtml(str).replace(/ /g, '  ').replace(/\n/g, '
    ')) - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - res.end(html); + var isInspect = !err.stack && String(err) === toString.call(err) + var errorHtml = !isInspect + ? escapeHtmlBlock(str.split('\n', 1)[0] || 'Error') + : 'Error' + var stack = !isInspect + ? String(str).split('\n').slice(1) + : [str] + var stackHtml = stack + .map(function (v) { return '
  • ' + escapeHtmlBlock(v) + '
  • ' }) + .join('') + var body = html + .replace('{style}', style) + .replace('{stack}', stackHtml) + .replace('{title}', escapeHtml(exports.title)) + .replace('{statusCode}', res.statusCode) + .replace(/\{error\}/g, errorHtml) + res.setHeader('Content-Type', 'text/html; charset=utf-8') + res.end(body) }); }); // json @@ -145,6 +154,17 @@ exports = module.exports = function errorHandler(options) { exports.title = 'Connect'; +/** + * Escape a block of HTML, preserving whitespace. + * @api private + */ + +function escapeHtmlBlock(str) { + return escapeHtml(str) + .replace(doubleSpaceGlobalRegExp, '  ') + .replace(newLineGlobalRegExp, '
    ') +} + /** * Stringify a value. * @api private diff --git a/test/test.js b/test/test.js index a34ba56..5bf0e66 100644 --- a/test/test.js +++ b/test/test.js @@ -106,9 +106,9 @@ describe('errorHandler()', function () { .get('/') .set('Accept', 'text/html') .expect('Content-Type', /text\/html/) - .expect(//) - .expect(/Error: boom!/) - .expect(/    at/) + .expect(/<title>Error: boom!<\/title>/) + .expect(/<h2><em>500<\/em> Error: boom!<\/h2>/) + .expect(/<li>    at/) .end(done) }) })