diff --git a/README.md b/README.md index 016cd36..d82a421 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ limiter(options) - `total`: `Number` allowed number of requests before getting rate limited - `expire`: `Number` amount of time in `ms` before the rate-limited is reset - `whitelist`: `function(req)` optional param allowing the ability to whitelist. return `boolean`, `true` to whitelist, `false` to passthru to limiter. - + - `skipHeaders`: `Boolean` whether to skip sending HTTP headers for rate limits () ### Examples ``` js @@ -89,6 +89,18 @@ limiter({ return !!req.user.is_admin } }) + +// skip sending HTTP limit headers +limiter({ + path: '/delete/thing', + method: 'post', + lookup: 'user.id', + whitelist: function (req) { + return !!req.user.is_admin + }, + skipHeaders: true +}) + ``` ### as direct middleware diff --git a/index.js b/index.js index 78a39f2..98dfd2c 100644 --- a/index.js +++ b/index.js @@ -28,14 +28,17 @@ module.exports = function (app, db) { limit.remaining = Math.max(Number(limit.remaining) - 1, 0) db.set(key, JSON.stringify(limit), function () { - res.set('X-RateLimit-Limit', limit.total) - res.set('X-RateLimit-Remaining', limit.remaining) + if (!opts.skipHeaders) { + res.set('X-RateLimit-Limit', limit.total) + res.set('X-RateLimit-Remaining', limit.remaining) + } if (limit.remaining) return next() var after = (limit.reset - Date.now()) / 1000 - res.set('Retry-After', after) + if (!opts.skipHeaders) res.set('Retry-After', after) + res.send(429, 'Rate limit exceeded') }) diff --git a/tests/index.js b/tests/index.js index 19b087a..ab51dd5 100644 --- a/tests/index.js +++ b/tests/index.js @@ -24,6 +24,7 @@ describe('rate-limiter', function () { it('should work', function (done) { var map = [10, 9, 8, 7, 6, 5, 4, 3, 2] var clock = sinon.useFakeTimers() + limiter({ path: '/route', method: 'get', @@ -69,4 +70,28 @@ describe('rate-limiter', function () { }) v.waterfall(out, done) }) + + describe('options', function() { + it('should process skipHeaders', function (done) { + limiter({ + path: '/route', + method: 'get', + lookup: ['connection.remoteAddress'], + total: 0, + expire: 1000 * 60 * 60, + skipHeaders: true + }) + + app.get('/route', function (req, res) { + res.send(200, 'hello') + }) + + request(app) + .get('/route') + .expect(function(res) { if ('X-RateLimit-Limit' in res.headers) return 'X-RateLimit-Limit Header not to be set' }) + .expect(function(res) { if ('X-RateLimit-Remaining' in res.headers) return 'X-RateLimit-Remaining Header not to be set' }) + .expect(function(res) { if ('Retry-After' in res.headers) return 'Retry-After not to be set' }) + .expect(429, done) + }) + }) })