UNPKG

1.95 kBJavaScriptView Raw
1
2var debug = require("../lib/log.js")
3, log = debug("app:ratelimit")
4, logBlock = debug("app:ratelimit:block")
5, logLeak = debug("app:ratelimit:leak")
6
7// Leaky bucket
8//
9// 14.37 Retry-After
10//
11// Retry-After = "Retry-After" ":" ( HTTP-date | delta-seconds )
12//
13// Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
14// Retry-After: 120
15
16
17module.exports = createRatelimit
18
19function createRatelimit(opts) {
20 opts = opts || {}
21
22 var counters = {}
23 , nulls = 0
24 , limit = opts.limit || 1000
25 , time = opts.time || 60*60*1000
26 , steps = opts.steps || 60
27 , field = opts.field || "ip"
28 , penalty = opts.penalty || 5000
29 , tickTime = (time/steps)|0
30 , leak = Math.ceil(limit/steps)
31
32 log("created", opts)
33 setInterval(tick, tickTime)
34
35 return ratelimit
36
37 function ratelimit(req, res, next) {
38 var key = req[field]
39 , remaining = limit - (counters[key] || (counters[key] = 0)) - 1
40
41 counters[key]++
42
43 if (remaining < leak) {
44 res.setHeader("Rate-Limit", limit)
45
46 if (remaining < 0) {
47 logBlock(field, key)
48 setTimeout(block, penalty, res, remaining)
49 } else {
50 res.setHeader("Rate-Limit-Remaining", remaining)
51 setTimeout(next, Math.ceil((leak - remaining) / leak * penalty))
52 }
53 } else {
54 next()
55 }
56 }
57
58 function block(res, remaining) {
59 res.statusCode = 429
60 res.setHeader("Retry-After", tickTime * Math.ceil(-remaining/leak))
61 res.end("Too Many Requests")
62 }
63
64 function tick() {
65 var key, counter, next
66 , count = 0
67 , clean = 0
68
69 if (nulls > 1000) {
70 next = {}
71 for (key in counters) if (counters[key] > leak) {
72 count++
73 next[key] = counters[key] - leak
74 } else clean++
75 nulls = 0
76 counters = next
77 } else {
78 for (key in counters) if (null !== (counter = counters[key])) {
79 if (counter > leak) {
80 count++
81 counters[key] -= leak
82 } else {
83 clean++
84 counters[key] = null
85 }
86 }
87 nulls += clean
88 }
89 logLeak("leak:%s clean:%s size:%s", leak, clean, count)
90 }
91}
92
93
94