rack-throttle 0.6.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a65f5195779a2af8c7340f1e52dd0c19e6036e234eeaf934518a307b05a208e4
4
- data.tar.gz: e69a0f3ee004f59b3a6808f9165a2c82b1729dde0ed344e7192998eb5c522f3a
3
+ metadata.gz: 9ccafa1280d85d26c5eae882f32bb0265a29805def1e6c9ce90af319fc37a6ac
4
+ data.tar.gz: f1177b0985521a49adf24904e4a0879e5c702f5c74e5f19c4bb8114a47ba39c9
5
5
  SHA512:
6
- metadata.gz: 0e0a36ff42888850b8e1532133706342637e070998d815ff5358a7a36235a3c7a4eabe5f0514ad463bdb7fea13e84ce4ce21b63e47f7352be5c03877c4c3ffb1
7
- data.tar.gz: 4d84b627410ff12bf7a81ac3ad19c681397287748d4d9306d1d5f447a918849488b04bb1b33f1057018a4519abbc309460aa109772193c7c4a81e13c23fe65bf
6
+ metadata.gz: 99a90f702ddb62295ce89f7ae21959ceaedd37583d683b7f35c04419d32e5827897e60a49918b265519d8e257cba3537d8bb8d0f55734498da4ee6d0fcddd89d
7
+ data.tar.gz: ef6d7c1b0a61a5a288f1707fa6dcf37f0a71dd37adc508cd8869ac37873d60fa6badd072749f27ef52c372ba0949f3b5262e355809b99606e11384f6ff946ea7
data/README.md ADDED
@@ -0,0 +1,331 @@
1
+ DEPRECATED We suggest using rack-attack instead
2
+ ===============================================
3
+
4
+ <https://github.com/rack/rack-attack> Accomplishes the same goal as rack-throttle,
5
+ but has more active maintenance, usage, and maturity. Please think about using rack-attack
6
+ over rack-throttle.
7
+
8
+ rack-throttle will still continue to exist to support legacy ruby applications (<2.3), but
9
+ will not be getting new features added as it exists strictly to support existing apps.
10
+
11
+ HTTP Request Rate Limiter for Rack Applications
12
+ ===============================================
13
+
14
+ This is [Rack][] middleware that provides logic for rate-limiting incoming
15
+ HTTP requests to Rack applications. You can use `Rack::Throttle` with any
16
+ Ruby web framework based on Rack, including with Ruby on Rails and with
17
+ Sinatra.
18
+
19
+ * <https://github.com/dryruby/rack-throttle>
20
+
21
+ Features
22
+ --------
23
+
24
+ * Throttles a Rack application by enforcing a minimum time interval between
25
+ subsequent HTTP requests from a particular client, as well as by defining
26
+ a maximum number of allowed HTTP requests per a given time period (per minute,
27
+ hourly, or daily).
28
+ * Compatible with any Rack application and any Rack-based framework.
29
+ * Stores rate-limiting counters in any key/value store implementation that
30
+ responds to `#[]`/`#[]=` (like Ruby's hashes) or to `#get`/`#set` (like
31
+ memcached or Redis).
32
+ * Compatible with the [gdbm][] binding included in Ruby's standard library.
33
+ * Compatible with the [memcached][], [memcache-client][], [memcache][] and
34
+ [redis][] gems.
35
+ * Compatible with [Heroku][]'s [memcached add-on][Heroku memcache]
36
+ (currently available as a free beta service).
37
+
38
+ Examples
39
+ --------
40
+
41
+ ### Adding throttling to a Rails application
42
+
43
+ ```ruby
44
+ # config/application.rb
45
+ require 'rack/throttle'
46
+
47
+ class Application < Rails::Application
48
+ config.middleware.use Rack::Throttle::Interval
49
+ end
50
+ ```
51
+
52
+ ### Adding throttling to a Sinatra application
53
+
54
+ ```ruby
55
+ #!/usr/bin/env ruby -rubygems
56
+ require 'sinatra'
57
+ require 'rack/throttle'
58
+
59
+ use Rack::Throttle::Interval
60
+
61
+ get('/hello') { "Hello, world!\n" }
62
+ ```
63
+
64
+ ### Adding throttling to a Rackup application
65
+
66
+ ```ruby
67
+ #!/usr/bin/env rackup
68
+ require 'rack/throttle'
69
+
70
+ use Rack::Throttle::Interval
71
+
72
+ run lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, world!\n"] }
73
+ ```
74
+
75
+ ### Enforcing a minimum 3-second interval between requests
76
+
77
+ ```ruby
78
+ use Rack::Throttle::Interval, :min => 3.0
79
+ ```
80
+
81
+ ### Allowing a maximum of 1 request per second
82
+
83
+ ```ruby
84
+ use Rack::Throttle::Second, :max => 1
85
+ ```
86
+
87
+ ### Allowing a maximum of 60 requests per minute
88
+
89
+ ```ruby
90
+ use Rack::Throttle::Minute, :max => 60
91
+ ```
92
+
93
+ ### Allowing a maximum of 100 requests per hour
94
+
95
+ ```ruby
96
+ use Rack::Throttle::Hourly, :max => 100
97
+ ```
98
+
99
+ ### Allowing a maximum of 1,000 requests per day
100
+
101
+ ```ruby
102
+ use Rack::Throttle::Daily, :max => 1000
103
+ ```
104
+
105
+ ### Combining various throttling constraints into one overall policy
106
+
107
+ ```ruby
108
+ use Rack::Throttle::Daily, :max => 1000 # requests
109
+ use Rack::Throttle::Hourly, :max => 100 # requests
110
+ use Rack::Throttle::Minute, :max => 60 # requests
111
+ use Rack::Throttle::Second, :max => 1 # requests
112
+ use Rack::Throttle::Interval, :min => 3.0 # seconds
113
+ ```
114
+
115
+ ### Storing the rate-limiting counters in a GDBM database
116
+
117
+ ```ruby
118
+ require 'gdbm'
119
+
120
+ use Rack::Throttle::Interval, :cache => GDBM.new('tmp/throttle.db')
121
+ ```
122
+
123
+ ### Storing the rate-limiting counters on a Memcached server
124
+
125
+ ```ruby
126
+ require 'memcached'
127
+
128
+ use Rack::Throttle::Interval, :cache => Memcached.new, :key_prefix => :throttle
129
+ ```
130
+
131
+ ### Storing the rate-limiting counters on a Redis server
132
+
133
+ ```ruby
134
+ require 'redis'
135
+
136
+ use Rack::Throttle::Interval, :cache => Redis.new, :key_prefix => :throttle
137
+ ```
138
+
139
+ Throttling Strategies
140
+ ---------------------
141
+
142
+ `Rack::Throttle` supports four built-in throttling strategies:
143
+
144
+ * `Rack::Throttle::Interval`: Throttles the application by enforcing a
145
+ minimum interval (by default, 1 second) between subsequent HTTP requests.
146
+ * `Rack::Throttle::Hourly`: Throttles the application by defining a
147
+ maximum number of allowed HTTP requests per hour (by default, 3,600
148
+ requests per 60 minutes, which works out to an average of 1 request per
149
+ second).
150
+ * `Rack::Throttle::Daily`: Throttles the application by defining a
151
+ maximum number of allowed HTTP requests per day (by default, 86,400
152
+ requests per 24 hours, which works out to an average of 1 request per
153
+ second).
154
+ * `Rack::Throttle::Minute`: Throttles the application by defining a
155
+ maximum number of allowed HTTP requests per minute (by default, 60
156
+ requests per 1 minute, which works out to an average of 1 request per
157
+ second).
158
+ * `Rack::Throttle::Second`: Throttles the application by defining a
159
+ maximum number of allowed HTTP requests per second (by default, 1
160
+ request per second).
161
+ * `Rack::Throttle::Rules`: Throttles the application by defining
162
+ different rules of allowed HTTP request per time_window based on the
163
+ request method and the request paths, or use a default.
164
+
165
+ You can fully customize the implementation details of any of these strategies
166
+ by simply subclassing one of the aforementioned default implementations.
167
+ And, of course, should your application-specific requirements be
168
+ significantly more complex than what we've provided for, you can also define
169
+ entirely new kinds of throttling strategies by subclassing the
170
+ `Rack::Throttle::Limiter` base class directly.
171
+
172
+ ### Example
173
+
174
+ Customize the `max_per_second` to be different depending on the request's method.
175
+
176
+ ```ruby
177
+ class Rack::Throttle::RequestMethod < Rack::Throttle::Second
178
+
179
+ def max_per_second(request = nil)
180
+ return (options[:max_per_second] || options[:max] || 1) unless request
181
+ if request.request_method == "POST"
182
+ 4
183
+ else
184
+ 10
185
+ end
186
+ end
187
+ alias_method :max_per_window, :max_per_second
188
+
189
+ end
190
+ ```
191
+
192
+ Passing the correct options for `Rules` strategy.
193
+
194
+ ```ruby
195
+ rules = [
196
+ { method: "POST", limit: 5 },
197
+ { method: "GET", limit: 10 },
198
+ { method: "GET", path: "/users/.*/profile", limit: 3 },
199
+ { method: "GET", path: "/users/.*/reset_password", limit: 1 }
200
+ { method: "GET", path: "/external/callback", whitelisted: true }
201
+ ]
202
+ ip_whitelist = [
203
+ "1.2.3.4",
204
+ "5.6.7.8"
205
+ ]
206
+ default = 10
207
+
208
+
209
+ use Rack::Throttle::Rules, rules: rules, ip_whitelist: ip_whitelist, default: default
210
+ ```
211
+
212
+ This configuration would allow a maximum of 3 profile requests per second (default), i
213
+ 1 reset password requests per second, 5 POST and 10 GET requests per second
214
+ (always also based on the IPaddress). Additionally it would whitelist the external callback
215
+ and add a ip-whitelisting for the given ips.
216
+
217
+ Rules are checked in this order:
218
+ * ip whitelist
219
+ * rules with `paths`,
220
+ * rules with `methods` only,
221
+ * `default`.
222
+
223
+ It is possible to set the time window for this strategy to: `:second` (default), `:minute`, `:hour` or `:day`, to change the check interval to these windows.
224
+
225
+ ```ruby
226
+ use Rack::Throttle::Rules, limits: limits, time_window: :minute
227
+ ```
228
+
229
+
230
+ HTTP Client Identification
231
+ --------------------------
232
+
233
+ The rate-limiting counters stored and maintained by `Rack::Throttle` are
234
+ keyed to unique HTTP clients.
235
+
236
+ By default, HTTP clients are uniquely identified by their IP address as
237
+ returned by `Rack::Request#ip`. If you wish to instead use a more granular,
238
+ application-specific identifier such as a session key or a user account
239
+ name, you need only subclass a throttling strategy implementation and
240
+ override the `#client_identifier` method.
241
+
242
+ HTTP Response Codes and Headers
243
+ -------------------------------
244
+
245
+ ### 403 Forbidden (Rate Limit Exceeded)
246
+
247
+ When a client exceeds their rate limit, `Rack::Throttle` by default returns
248
+ a "403 Forbidden" response with an associated "Rate Limit Exceeded" message
249
+ in the response body.
250
+
251
+ An HTTP 403 response means that the server understood the request, but is
252
+ refusing to respond to it and an accompanying message will explain why.
253
+ This indicates an error on the client's part in exceeding the rate limits
254
+ outlined in the acceptable use policy for the site, service, or API.
255
+
256
+ ### 503 Service Unavailable (Rate Limit Exceeded)
257
+
258
+ However, there exists a widespread practice of instead returning a "503
259
+ Service Unavailable" response when a client exceeds the set rate limits.
260
+ This is technically dubious because it indicates an error on the server's
261
+ part, which is certainly not the case with rate limiting - it was the client
262
+ that committed the oops, not the server.
263
+
264
+ An HTTP 503 response would be correct in situations where the server was
265
+ genuinely overloaded and couldn't handle more requests, but for rate
266
+ limiting an HTTP 403 response is more appropriate. Nonetheless, if you think
267
+ otherwise, `Rack::Throttle` does allow you to override the returned HTTP
268
+ status code by passing in a `:code => 503` option when constructing a
269
+ `Rack::Throttle::Limiter` instance.
270
+
271
+ Dependencies
272
+ ------------
273
+
274
+ * [Rack](http://rubygems.org/gems/rack) (>= 1.0.0)
275
+
276
+ Installation
277
+ ------------
278
+
279
+ The recommended installation method is via [RubyGems](http://rubygems.org/).
280
+ To install the latest official release of the gem, do:
281
+
282
+ % [sudo] gem install rack-throttle
283
+
284
+ Authors
285
+ -------
286
+
287
+ * [Arto Bendiken](https://gratipay.com/bendiken) - <http://ar.to/>
288
+
289
+ Contributors
290
+ ------------
291
+
292
+ * [Brendon Murphy](https://github.com/bemurphy)
293
+ * [Hendrik Kleinwaechter](https://github.com/hendricius)
294
+ * [Karel Minarik](https://github.com/karmi)
295
+ * [Keita Urashima](https://github.com/ursm)
296
+ * [Leonid Beder](https://github.com/lbeder)
297
+ * [TJ Singleton](https://github.com/tjsingleton)
298
+ * [Winfield Peterson](https://github.com/wpeterson)
299
+ * [Dean Galvin](https://github.com/freekingdean)
300
+
301
+ Contributing
302
+ ------------
303
+
304
+ * Do your best to adhere to the existing coding conventions and idioms.
305
+ * Don't use hard tabs, and don't leave trailing whitespace on any line.
306
+ Before committing, run `git diff --check` to make sure of this.
307
+ * Do document every method you add using [YARD][] annotations. Read the
308
+ [tutorial][YARD-GS] or just look at the existing code for examples.
309
+ * Don't touch the gemspec or `VERSION` files. If you need to change them,
310
+ do so on your private branch only.
311
+ * Do feel free to add yourself to the `CREDITS` file and the
312
+ corresponding list in the the `README`. Alphabetical order applies.
313
+ * Don't touch the `AUTHORS` file. If your contributions are significant
314
+ enough, be assured we will eventually add you in there.
315
+
316
+ License
317
+ -------
318
+
319
+ This is free and unencumbered public domain software. For more information,
320
+ see <http://unlicense.org/> or the accompanying `UNLICENSE` file.
321
+
322
+ [Rack]: http://rack.rubyforge.org/
323
+ [gdbm]: http://ruby-doc.org/stdlib/libdoc/gdbm/rdoc/classes/GDBM.html
324
+ [memcached]: http://rubygems.org/gems/memcached
325
+ [memcache-client]: http://rubygems.org/gems/memcache-client
326
+ [memcache]: http://rubygems.org/gems/memcache
327
+ [redis]: http://rubygems.org/gems/redis
328
+ [Heroku]: http://heroku.com/
329
+ [Heroku memcache]: http://docs.heroku.com/memcache
330
+ [YARD]: http://yardoc.org/
331
+ [YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.0
1
+ 0.7.1
@@ -23,6 +23,7 @@ module Rack; module Throttle
23
23
  # @option options [String] :message ("Rate Limit Exceeded")
24
24
  # @option options [String] :type ("text/plain; charset=utf-8")
25
25
  def initialize(app, options = {})
26
+ warn "[DEPRECATION] `rack-throttle` is deprecated. Please use consider using `rack-attack` https://github.com/rack/rack-attack instead."
26
27
  @app, @options = app, options
27
28
  end
28
29
 
@@ -14,7 +14,7 @@ module Rack
14
14
  def rules
15
15
  @rules ||= begin
16
16
  rs = options[:rules]
17
- rs.sort_by { |r| r[:path].to_s }.reverse
17
+ rs.sort_by { |r| [r[:proc].to_s, r[:path].to_s] }.reverse
18
18
  end
19
19
  end
20
20
 
@@ -32,7 +32,7 @@ module Rack
32
32
 
33
33
  def whitelisted?(request)
34
34
  return true if ip_whitelisted?(IPAddr.new(ip(request)))
35
- return true if path_whitelisted?(request)
35
+ return true if rule_whitelisted?(request)
36
36
  false
37
37
  end
38
38
 
@@ -40,7 +40,7 @@ module Rack
40
40
  !!ips.find { |ip| ip.include?(request_ip) }
41
41
  end
42
42
 
43
- def path_whitelisted?(request)
43
+ def rule_whitelisted?(request)
44
44
  rule = rule_for(request)
45
45
  rule ? rule[:whitelisted] : false
46
46
  end
@@ -48,7 +48,8 @@ module Rack
48
48
  def rule_for(request)
49
49
  rules.find do |rule|
50
50
  next unless rule[:method] == request.request_method.to_s
51
- next unless path_matches?(rule, request.path.to_s)
51
+ next if rule[:proc] && rule[:proc].call(request) == false
52
+ next if rule[:path] && !path_matches?(rule, request.path.to_s)
52
53
  rule
53
54
  end
54
55
  end
@@ -66,11 +67,23 @@ module Rack
66
67
 
67
68
  def client_identifier(request)
68
69
  if (rule = rule_for(request))
69
- "#{ip(request)}_#{rule[:method]}_#{rule[:path]}"
70
+ client_identifier_for_rule(request, rule)
70
71
  else
71
72
  ip(request)
72
73
  end
73
74
  end
75
+
76
+ def client_identifier_for_rule(request, rule)
77
+ if rule[:proc]
78
+ "#{rule[:method]}_#{rule[:proc].call(request)}"
79
+ elsif rule[:path]
80
+ "#{ip(request)}_#{rule[:method]}_#{rule[:path]}"
81
+ elsif rule[:method]
82
+ "#{ip(request)}_#{rule[:method]}"
83
+ else
84
+ raise NotImplementedError
85
+ end
86
+ end
74
87
 
75
88
  def ip(request)
76
89
  request.ip.to_s
@@ -1,8 +1,8 @@
1
1
  module Rack; module Throttle
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 6
5
- TINY = 0
4
+ MINOR = 7
5
+ TINY = 1
6
6
  EXTRA = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
data/lib/rack/throttle.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rack'
2
2
 
3
3
  module Rack
4
+ #<b>DEPRECATED:</b> rack-throttle is deprecated please consider using rack-attack
4
5
  module Throttle
5
6
  autoload :Limiter, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/limiter'
6
7
  autoload :Interval, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/interval'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-throttle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arto Bendiken
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-20 00:00:00.000000000 Z
11
+ date: 2023-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -101,7 +101,7 @@ extensions: []
101
101
  extra_rdoc_files: []
102
102
  files:
103
103
  - AUTHORS
104
- - README
104
+ - README.md
105
105
  - UNLICENSE
106
106
  - VERSION
107
107
  - lib/rack/throttle.rb
@@ -114,11 +114,14 @@ files:
114
114
  - lib/rack/throttle/second.rb
115
115
  - lib/rack/throttle/time_window.rb
116
116
  - lib/rack/throttle/version.rb
117
- homepage: https://github.com/bendiken/rack-throttle
117
+ homepage: https://github.com/dryruby/rack-throttle
118
118
  licenses:
119
119
  - Public Domain
120
120
  metadata: {}
121
- post_install_message:
121
+ post_install_message: |
122
+ rack-throttle is no longer under active development. Please consider
123
+ using https://github.com/rack/rack-attack instead as it is
124
+ more feature rich & well supported.
122
125
  rdoc_options: []
123
126
  require_paths:
124
127
  - lib
@@ -133,9 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
136
  - !ruby/object:Gem::Version
134
137
  version: '0'
135
138
  requirements: []
136
- rubyforge_project:
137
- rubygems_version: 2.7.6
138
- signing_key:
139
+ rubygems_version: 3.3.25
140
+ signing_key:
139
141
  specification_version: 4
140
142
  summary: HTTP request rate limiter for Rack applications.
141
143
  test_files: []
data/README DELETED
@@ -1 +0,0 @@
1
- ./README.md