diff --git a/index.js b/index.js
index f628e42..7fdba82 100644
--- a/index.js
+++ b/index.js
@@ -28,9 +28,12 @@ var DOUBLE_SPACE_REGEXP = /\x20{2}/g
var NEWLINE_REGEXP = /\n/g
/* istanbul ignore next */
-var defer = typeof setImmediate === 'function'
- ? setImmediate
- : function (fn) { process.nextTick(fn.bind.apply(fn, arguments)) }
+var defer =
+ typeof setImmediate === 'function'
+ ? setImmediate
+ : function (fn) {
+ process.nextTick(fn.bind.apply(fn, arguments))
+ }
var isFinished = onFinished.isFinished
/**
@@ -41,20 +44,22 @@ var isFinished = onFinished.isFinished
*/
function createHtmlDocument (message) {
- var body = escapeHtml(message)
- .replace(NEWLINE_REGEXP, '
')
- .replace(DOUBLE_SPACE_REGEXP, ' ')
+ var body = escapeHtml(message).replace(NEWLINE_REGEXP, '
').replace(DOUBLE_SPACE_REGEXP, ' ')
- return '\n' +
+ return (
+ '\n' +
'\n' +
'
' + body + '\n' + + '
' + + body + + '\n' + '\n' + '\n' + ) } /** @@ -175,6 +180,13 @@ function getErrorMessage (err, status, env) { // use err.stack, which typically includes err.message msg = err.stack + // if error cause included + if (err && err.cause && err.cause.stack) { + msg += '\n[cause]: ' + err.cause.stack + } else if (err && err.stack) { + msg += '\n[stack]: ' + err.stack + } + // fallback to err.toString() when possible if (!msg && typeof err.toString === 'function') { msg = err.toString() @@ -253,9 +265,7 @@ function getResponseStatusCode (res) { */ function headersSent (res) { - return typeof res.headersSent !== 'boolean' - ? Boolean(res._header) - : res.headersSent + return typeof res.headersSent !== 'boolean' ? Boolean(res._header) : res.headersSent } /** diff --git a/test/test.js b/test/test.js index a815654..8975427 100644 --- a/test/test.js +++ b/test/test.js @@ -1,4 +1,3 @@ - var Buffer = require('safe-buffer').Buffer var finalhandler = require('..') var http = require('http') @@ -14,46 +13,60 @@ var shouldHaveStatusMessage = utils.shouldHaveStatusMessage var shouldNotHaveBody = utils.shouldNotHaveBody var shouldNotHaveHeader = utils.shouldNotHaveHeader -var describeStatusMessage = !/statusMessage/.test(http.IncomingMessage.toString()) - ? describe.skip - : describe +var describeStatusMessage = !/statusMessage/.test(http.IncomingMessage.toString()) ? describe.skip : describe describe('finalhandler(req, res)', function () { describe('headers', function () { it('should ignore err.headers without status code', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo' } - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo' } + }) + ) + ) .get('/') .expect(shouldNotHaveHeader('X-Custom-Header')) .expect(500, done) }) it('should ignore err.headers with invalid res.status', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo' }, - status: 601 - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo' }, + status: 601 + }) + ) + ) .get('/') .expect(shouldNotHaveHeader('X-Custom-Header')) .expect(500, done) }) it('should ignore err.headers with invalid res.statusCode', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo' }, - statusCode: 601 - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo' }, + statusCode: 601 + }) + ) + ) .get('/') .expect(shouldNotHaveHeader('X-Custom-Header')) .expect(500, done) }) it('should include err.headers with err.status', function (done) { - request(createServer(createError('oops!', { - headers: { 'X-Custom-Header': 'foo=500', 'X-Custom-Header2': 'bar' }, - status: 500 - }))) + request( + createServer( + createError('oops!', { + headers: { 'X-Custom-Header': 'foo=500', 'X-Custom-Header2': 'bar' }, + status: 500 + }) + ) + ) .get('/') .expect('X-Custom-Header', 'foo=500') .expect('X-Custom-Header2', 'bar') @@ -61,20 +74,28 @@ describe('finalhandler(req, res)', function () { }) it('should include err.headers with err.statusCode', function (done) { - request(createServer(createError('too many requests', { - headers: { 'Retry-After': '5' }, - statusCode: 429 - }))) + request( + createServer( + createError('too many requests', { + headers: { 'Retry-After': '5' }, + statusCode: 429 + }) + ) + ) .get('/') .expect('Retry-After', '5') .expect(429, done) }) it('should ignore err.headers when not an object', function (done) { - request(createServer(createError('oops!', { - headers: 'foobar', - statusCode: 500 - }))) + request( + createServer( + createError('oops!', { + headers: 'foobar', + statusCode: 500 + }) + ) + ) .get('/') .expect(500, done) }) @@ -82,95 +103,131 @@ describe('finalhandler(req, res)', function () { describe('status code', function () { it('should 404 on no error', function (done) { - request(createServer()) - .get('/') - .expect(404, done) + request(createServer()).get('/').expect(404, done) }) it('should 500 on error', function (done) { - request(createServer(createError())) - .get('/') - .expect(500, done) + request(createServer(createError())).get('/').expect(500, done) }) it('should use err.statusCode', function (done) { - request(createServer(createError('nope', { - statusCode: 400 - }))) + request( + createServer( + createError('nope', { + statusCode: 400 + }) + ) + ) .get('/') .expect(400, done) }) it('should ignore non-error err.statusCode code', function (done) { - request(createServer(createError('created', { - statusCode: 201 - }))) + request( + createServer( + createError('created', { + statusCode: 201 + }) + ) + ) .get('/') .expect(500, done) }) it('should ignore non-numeric err.statusCode', function (done) { - request(createServer(createError('oops', { - statusCode: 'oh no' - }))) + request( + createServer( + createError('oops', { + statusCode: 'oh no' + }) + ) + ) .get('/') .expect(500, done) }) it('should use err.status', function (done) { - request(createServer(createError('nope', { - status: 400 - }))) + request( + createServer( + createError('nope', { + status: 400 + }) + ) + ) .get('/') .expect(400, done) }) it('should use err.status over err.statusCode', function (done) { - request(createServer(createError('nope', { - status: 400, - statusCode: 401 - }))) + request( + createServer( + createError('nope', { + status: 400, + statusCode: 401 + }) + ) + ) .get('/') .expect(400, done) }) it('should set status to 500 when err.status < 400', function (done) { - request(createServer(createError('oops', { - status: 202 - }))) + request( + createServer( + createError('oops', { + status: 202 + }) + ) + ) .get('/') .expect(500, done) }) it('should set status to 500 when err.status > 599', function (done) { - request(createServer(createError('oops', { - status: 601 - }))) + request( + createServer( + createError('oops', { + status: 601 + }) + ) + ) .get('/') .expect(500, done) }) it('should use err.statusCode over invalid err.status', function (done) { - request(createServer(createError('nope', { - status: 50, - statusCode: 410 - }))) + request( + createServer( + createError('nope', { + status: 50, + statusCode: 410 + }) + ) + ) .get('/') .expect(410, done) }) it('should ignore non-error err.status code', function (done) { - request(createServer(createError('created', { - status: 201 - }))) + request( + createServer( + createError('created', { + status: 201 + }) + ) + ) .get('/') .expect(500, done) }) it('should ignore non-numeric err.status', function (done) { - request(createServer(createError('oops', { - status: 'oh no' - }))) + request( + createServer( + createError('oops', { + status: 'oh no' + }) + ) + ) .get('/') .expect(500, done) }) @@ -178,10 +235,7 @@ describe('finalhandler(req, res)', function () { describeStatusMessage('status message', function () { it('should be "Not Found" on no error', function (done) { - request(createServer()) - .get('/') - .expect(shouldHaveStatusMessage('Not Found')) - .expect(404, done) + request(createServer()).get('/').expect(shouldHaveStatusMessage('Not Found')).expect(404, done) }) it('should be "Internal Server Error" on error', function (done) { @@ -192,9 +246,13 @@ describe('finalhandler(req, res)', function () { }) it('should be "Bad Request" when err.statusCode = 400', function (done) { - request(createServer(createError('oops', { - status: 400 - }))) + request( + createServer( + createError('oops', { + status: 400 + }) + ) + ) .get('/') .expect(shouldHaveStatusMessage('Bad Request')) .expect(400, done) @@ -222,7 +280,7 @@ describe('finalhandler(req, res)', function () { it('should escape method and pathname characters', function (done) { rawrequest(createServer()) - .get('/
Cannot GET \/%3Cla'me%3E<\/pre>/, done)
})
@@ -263,25 +321,15 @@ describe('finalhandler(req, res)', function () {
})
it('should handle HEAD', function (done) {
- request(createServer())
- .head('/foo')
- .expect(404)
- .expect(shouldNotHaveBody())
- .end(done)
+ request(createServer()).head('/foo').expect(404).expect(shouldNotHaveBody()).end(done)
})
it('should include X-Content-Type-Options header', function (done) {
- request(createServer())
- .get('/foo')
- .expect('X-Content-Type-Options', 'nosniff')
- .expect(404, done)
+ request(createServer()).get('/foo').expect('X-Content-Type-Options', 'nosniff').expect(404, done)
})
it('should include Content-Security-Policy header', function (done) {
- request(createServer())
- .get('/foo')
- .expect('Content-Security-Policy', "default-src 'none'")
- .expect(404, done)
+ request(createServer()).get('/foo').expect('Content-Security-Policy', "default-src 'none'").expect(404, done)
})
it('should not hang/error if there is a request body', function (done) {
@@ -340,9 +388,11 @@ describe('finalhandler(req, res)', function () {
var err = createError('boom!', {
status: 501
})
- request(createServer(err, {
- env: 'production'
- }))
+ request(
+ createServer(err, {
+ env: 'production'
+ })
+ )
.get('/foo')
.expect(501, /Not Implemented<\/pre>/, done)
})
@@ -399,9 +449,7 @@ describe('finalhandler(req, res)', function () {
done(new Error('oops'))
})
- request(server)
- .get('/foo')
- .expect(503, done)
+ request(server).get('/foo').expect(503, done)
})
it('should convert to 500 is not a number', function (done) {
@@ -411,9 +459,7 @@ describe('finalhandler(req, res)', function () {
done(new Error('oops'))
})
- request(server)
- .get('/foo')
- .expect(500, done)
+ request(server).get('/foo').expect(500, done)
})
it('should override with err.status', function (done) {
@@ -426,18 +472,18 @@ describe('finalhandler(req, res)', function () {
done(err)
})
- request(server)
- .get('/foo')
- .expect(414, done)
+ request(server).get('/foo').expect(414, done)
})
it('should default body to status message in production', function (done) {
var err = createError('boom!', {
status: 509
})
- request(createServer(err, {
- env: 'production'
- }))
+ request(
+ createServer(err, {
+ env: 'production'
+ })
+ )
.get('/foo')
.expect(509, /Bandwidth Limit Exceeded<\/pre>/, done)
})
@@ -451,9 +497,7 @@ describe('finalhandler(req, res)', function () {
done(new Error('oops'))
})
- request(server)
- .get('/foo')
- .expect(500, done)
+ request(server).get('/foo').expect(500, done)
})
})
})
@@ -466,11 +510,7 @@ describe('finalhandler(req, res)', function () {
done()
})
- request(server)
- .get('/foo')
- .expect(404)
- .expect('Server', 'foobar')
- .end(done)
+ request(server).get('/foo').expect(404).expect('Server', 'foobar').end(done)
})
it('should override content-type and length', function (done) {
@@ -520,9 +560,7 @@ describe('finalhandler(req, res)', function () {
})
})
- request(server)
- .get('/foo')
- .expect(301, '01', done)
+ request(server).get('/foo').expect(301, '01', done)
})
it('should terminate on error', function (done) {
@@ -531,10 +569,12 @@ describe('finalhandler(req, res)', function () {
res.statusCode = 301
res.write('0')
process.nextTick(function () {
- done(createError('too many requests', {
- status: 429,
- headers: { 'Retry-After': '5' }
- }))
+ done(
+ createError('too many requests', {
+ status: 429,
+ headers: { 'Retry-After': '5' }
+ })
+ )
res.end('1')
})
})
@@ -577,4 +617,17 @@ describe('finalhandler(req, res)', function () {
})
})
})
+
+ describe('should display cause in the Error output', function () {
+ it('should return error message with stack trace in development', function (done) {
+ process.env.NODE_ENV = 'development'
+ const err = new Error('foo', { cause: new Error('bar') })
+
+ const server = createServer(err)
+
+ request(server)
+ .get('/')
+ .expect(500, /[Error: bar]/, done)
+ })
+ })
})