Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,10 @@ morgan.token('type', function (req, res) { return req.headers['content-type'] })
Calling `morgan.token()` using the same name as an existing token will overwrite that
token definition.

The names `token`, `format`, and `compile` are reserved by morgan itself and cannot be
used as custom token names. Attempting to register a token with one of these names will
throw a `TypeError`.

The token function is expected to be called with the arguments `req` and `res`, representing
the HTTP request and HTTP response. Additionally, the token can accept further arguments of
its choosing to customize behavior.
Expand Down
15 changes: 15 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ module.exports.compile = compile
module.exports.format = format
module.exports.token = token

/**
* Names that must not be registered as custom tokens, because token()
* stores callbacks on the morgan export object itself.
* @private
*/
var RESERVED_TOKEN_NAMES = {
compile: true,
format: true,
token: true
}

/**
* Module dependencies.
* @private
Expand Down Expand Up @@ -585,6 +596,10 @@ function recordStartTime () {
*/

function token (name, fn) {
if (Object.prototype.hasOwnProperty.call(RESERVED_TOKEN_NAMES, name)) {
throw new TypeError('morgan.token cannot use reserved name "' + name + '"')
}

// wrap the token so its string output is always escaped for line-oriented
// logs, regardless of whether the format is a string or a function
morgan[name] = function tokenValue () {
Expand Down
30 changes: 30 additions & 0 deletions test/morgan.js
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,36 @@ describe('morgan.compile(format)', function () {
})
})

describe('morgan.token(name, fn)', function () {
describe('arguments', function () {
describe('name', function () {
it('should reject reserved names', function () {
assert.throws(morgan.token.bind(morgan, 'token', function () {}), /reserved name/)
assert.throws(morgan.token.bind(morgan, 'format', function () {}), /reserved name/)
assert.throws(morgan.token.bind(morgan, 'compile', function () {}), /reserved name/)
})

it('should not corrupt morgan.token after rejecting a reserved name', function () {
assert.throws(morgan.token.bind(morgan, 'token', function () {}), /reserved name/)

// morgan.token itself must still be a working function
assert.strictEqual(typeof morgan.token, 'function')

// and registering a normal token afterwards must still work
morgan.token('my-custom-token', function () { return 'custom-value' })
assert.strictEqual(typeof morgan['my-custom-token'], 'function')
assert.strictEqual(morgan['my-custom-token']({}, {}), 'custom-value')
})

it('should allow non-reserved names', function () {
morgan.token('some-other-token', function () { return 'value' })
assert.strictEqual(typeof morgan['some-other-token'], 'function')
assert.strictEqual(morgan['some-other-token']({}, {}), 'value')
})
})
})
})

function after (count, callback) {
var args = new Array(3)
var i = 0
Expand Down