Skip to content

Commit

Permalink
feat: honour "expose" property of http-errors
Browse files Browse the repository at this point in the history
This commit adds support for the "expose" property used by the
http-errors module, which allows developers to explicitly signal the
error message to be passed to the HTTP response for errors. This is
useful for certain errors (e.g., those with status code >=500) where the
original error message is otherwise suppressed by default.

Resolves: loopbackio#78
Signed-off-by: getsnoopy <[email protected]>
  • Loading branch information
getsnoopy committed Jul 18, 2022
1 parent 2f6144e commit 613a7ff
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 1 deletion.
7 changes: 6 additions & 1 deletion lib/data-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,12 @@ function fillClientError(data, err) {
}

function fillServerError(data, err) {
data.message = httpStatus[data.statusCode] || 'Unknown Error';
if (err.expose) {
data.name = httpStatus[data.statusCode] || 'Unknown Error';
data.message = err.message;
} else {
data.message = httpStatus[data.statusCode] || 'Unknown Error';
}
}

function fillSafeFields(data, err, safeFields) {
Expand Down
74 changes: 74 additions & 0 deletions test/handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,33 @@ describe('strong-error-handler', function() {
});
});

it('honours expose=true when status=5xx', function(done) {
// Mock an error reported by fs.readFile
const error = new ErrorWithProps({
name: 'Error',
message: 'ENOENT: no such file or directory, open "/etc/passwd"',
errno: -2,
code: 'ENOENT',
expose: true,
syscall: 'open',
path: '/etc/password',
});
givenErrorHandlerForError(error);

requestJson().end(function(err, res) {
if (err) return done(err);

expect(res.body).to.have.property('error');
expect(res.body.error).to.eql({
statusCode: 500,
name: 'Internal Server Error',
message: 'ENOENT: no such file or directory, open "/etc/passwd"',
});

done();
});
});

it('handles array argument as 500 when debug=false', function(done) {
const errors = [new Error('ERR1'), new Error('ERR2'), 'ERR STRING'];
givenErrorHandlerForError(errors);
Expand Down Expand Up @@ -679,6 +706,29 @@ describe('strong-error-handler', function() {
});
});

it('honours expose=true when status=5xx', function(done) {
const error = new ErrorWithProps({
name: 'Error',
message: 'Server out of disk space',
details: 'some details',
extra: 'sensitive data',
expose: true,
});
givenErrorHandlerForError(error);

requestHTML()
.end(function(err, res) {
expect(res.statusCode).to.eql(500);
const body = res.error.text;
expect(body).to.not.match(/some details/);
expect(body).to.not.match(/sensitive data/);
// only have the following
expect(body).to.match(/<title>Internal Server Error<\/title>/);
expect(body).to.match(/500(.*?)Server out of disk space/);
done();
});
});

function requestHTML(url) {
return request.get(url || '/')
.set('Accept', 'text/html')
Expand Down Expand Up @@ -754,6 +804,30 @@ describe('strong-error-handler', function() {
});
});

it('honours expose=true when status=5xx', function(done) {
const error = new ErrorWithProps({
name: 'Error',
message: 'Server out of disk space',
details: 'some details',
extra: 'sensitive data',
expose: true,
});
givenErrorHandlerForError(error);

requestXML()
.end(function(err, res) {
expect(res.statusCode).to.eql(500);
const body = res.error.text;
expect(body).to.not.match(/some details/);
expect(body).to.not.match(/sensitive data/);
// only have the following
expect(body).to.match(/<statusCode>500<\/statusCode>/);
expect(body).to.match(/<name>Internal Server Error<\/name>/);
expect(body).to.match(/<message>Server out of disk space<\/message>/);
done();
});
});

it('honors options.rootProperty', function(done) {
const error = new ErrorWithProps({
name: 'ValidationError',
Expand Down

0 comments on commit 613a7ff

Please sign in to comment.