Browse Source

Merge pull request #2 from roark31337/feature/skipHeaders

Add ability to set skipHeaders into the options to prevent the setting o...
develop
Dustin Diaz 10 years ago
parent
commit
2bb0855a74
  1. 14
      README.md
  2. 10
      index.js
  3. 48
      tests/index.js

14
README.md

@ -45,6 +45,8 @@ 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 ()
- `ignoreErrors`: `Boolean` whether errors generated from redis should allow the middleware to call next(). Defaults to false.
### Examples
@ -89,6 +91,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

10
index.js

@ -12,6 +12,7 @@ module.exports = function (app, db) {
var key = 'ratelimit:' + opts.path + ':' + opts.method + ':' + lookups
db.get(key, function (err, limit) {
if (err && opts.ignoreErrors) return next()
var now = Date.now()
limit = limit ? JSON.parse(limit) : {
total: opts.total,
@ -28,14 +29,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')
})

48
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,51 @@ 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)
})
it('should process ignoreErrors', function (done) {
limiter({
path: '/route',
method: 'get',
lookup: ['connection.remoteAddress'],
total: 10,
expire: 1000 * 60 * 60,
ignoreErrors: true
})
app.get('/route', function (req, res) {
res.send(200, 'hello')
})
sinon.stub(redis, 'get', function(key, callback) {
callback({err: true})
})
request(app)
.get('/route')
.expect(200, done)
})
})
})

Loading…
Cancel
Save