Skip to content

Commit

Permalink
Merge pull request #169 from sanyamdogra/header-standard
Browse files Browse the repository at this point in the history
Config for RateLimit standardization headers
  • Loading branch information
nfriedly committed Feb 13, 2020
2 parents 16716b4 + 3b46e2c commit 35a14bb
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ Enable headers for request limit (`X-RateLimit-Limit`) and current usage (`X-Rat

Defaults to `true`.

### draft_polli_ratelimit_headers

Enable headers conforming to the [ratelimit standardization proposal](https://tools.ietf.org/id/draft-polli-ratelimit-headers-01.html): `RateLimit-Limit`, `RateLimit-Remaining`, and, if the store supports it, `RateLimit-Reset`. May be used in conjunction with, or instead of the `headers` option.

Defaults to `false`, but will likely be changed in the next major release.

### keyGenerator

Function used to generate keys.
Expand Down Expand Up @@ -225,7 +231,6 @@ Available data stores are:
- [rate-limit-memcached](https://npmjs.org/package/rate-limit-memcached): A [Memcached](https://memcached.org/)-backed store.
- [rate-limit-mongo](https://www.npmjs.com/package/rate-limit-mongo): A [MongoDB](https://www.mongodb.com/)-backed store.


You may also create your own store. It must implement the following in order to function:

```js
Expand Down
11 changes: 11 additions & 0 deletions lib/express-rate-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ function RateLimit(options) {
message: "Too many requests, please try again later.",
statusCode: 429, // 429 status = Too Many Requests (RFC 6585)
headers: true, //Send custom rate limit header with limit and remaining
draft_polli_ratelimit_headers: false, //Support for the new RateLimit standardization headers
skipFailedRequests: false, // Do not count failed requests (status >= 400)
skipSuccessfulRequests: false, // Do not count successful requests (status < 400)
// allows to create custom keys (by default user IP is used)
Expand Down Expand Up @@ -85,6 +86,16 @@ function RateLimit(options) {
);
}
}
if (options.draft_polli_ratelimit_headers && !res.headersSent) {
res.setHeader("RateLimit-Limit", max);
res.setHeader("RateLimit-Remaining", req.rateLimit.remaining);
if (resetTime) {
const deltaSeconds = Math.ceil(
(resetTime.getTime() - Date.now()) / 1000
);
res.setHeader("RateLimit-Reset", Math.max(0, deltaSeconds));
}
}

if (options.skipFailedRequests || options.skipSuccessfulRequests) {
let decremented = false;
Expand Down
21 changes: 21 additions & 0 deletions test/express-rate-limit-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,27 @@ describe("express-rate-limit node module", function() {
);
});

it("should send correct ratelimit-limit and ratelimit-remaining", function(done) {
const limit = 5;
const windowMs = 60 * 1000; // 60 * 1000 = 1 minute
const app = createAppWith(
rateLimit({
windowMs: windowMs,
limit: limit,
draft_polli_ratelimit_headers: true
})
);
const expectedRemaining = 4;
const expectedResetSeconds = 60;
request(app)
.get("/")
.expect("ratelimit-limit", limit.toString())
.expect("ratelimit-remaining", expectedRemaining.toString())
.expect("ratelimit-reset", expectedResetSeconds.toString())
.expect(200, /response!/)
.end(done);
});

it("should refuse additional connections once IP has reached the max", function(done) {
createAppWith(
rateLimit({
Expand Down

0 comments on commit 35a14bb

Please sign in to comment.