@@ -230,19 +230,40 @@ Rack::Attack.blocklisted_response = lambda do |env|
230230end
231231
232232Rack ::Attack .throttled_response = lambda do |env |
233- # name and other data about the matched throttle
234- body = [
235- env[' rack.attack.matched' ],
236- env[' rack.attack.match_type' ],
237- env[' rack.attack.match_data' ]
238- ].inspect
233+ # NB: you have access to the name and other data about the matched throttle
234+ # env['rack.attack.matched'],
235+ # env['rack.attack.match_type'],
236+ # env['rack.attack.match_data']
239237
240238 # Using 503 because it may make attacker think that they have successfully
241239 # DOSed the site. Rack::Attack returns 429 for throttling by default
242- [ 503 , {}, [body ]]
240+ [ 503 , {}, [" Server Error \n " ]]
243241end
244242```
245243
244+ ### X-RateLimit headers for well-behaved clients
245+
246+ While Rack::Attack's primary focus is minimizing harm from abusive clients, it
247+ can also be used to return rate limit data that's helpful for well-behaved clients.
248+
249+ Here's an example response that includes conventional ` X-RateLimit-* ` headers:
250+
251+ ``` ruby
252+ Rack ::Attack .throttled_response = lambda do |env |
253+ now = Time .now
254+ match_data = env[' rack.attack.match_data' ]
255+
256+ headers = {
257+ ' X-RateLimit-Limit' => match_data[:limit ].to_s,
258+ ' X-RateLimit-Remaining' => ' 0' ,
259+ ' X-RateLimit-Reset' => (now + (match_data[:period ] - now.to_i % match_data[:period ])).to_s
260+ }
261+
262+ [ 429 , headers, [" Throttled\n " ]]
263+ end
264+ ```
265+
266+
246267For responses that did not exceed a throttle limit, Rack::Attack annotates the env with match data:
247268
248269``` ruby
0 commit comments