rack-throttle 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MDNkYTliNDNmN2ExYWQ1OWY3NjkyZDNkZTk0OTQ0ZGZiODk1ZWFiNw==
5
- data.tar.gz: !binary |-
6
- ODdlYzYyOGQwYzY2OGZiNDgyNzc4NWY3OTEzNDc2ZDFlYzZhZjE1ZA==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- NjUxNmJmMTBlNWU1MDk3ZjM2Zjc1YmEzNWJlYTYyYzBlMWQxNDFiOTgzMGMx
10
- YjM1OGQ5Mzk1ZjRlZDQxYzQxZjNiZDdlN2IzMjM2NDU3ZGRjZWUwZGJiYmQw
11
- ZDQ3NGYxNDNhZGJhZmQ3MzcyZGU4ZDgwYTg5OTE1NmNmYzZhMDg=
12
- data.tar.gz: !binary |-
13
- OTRmNWNlN2VkYWU0ODAyMTAzMmRjMmE0ZTllMmE3OTliODA5MmFkMTQxOGRm
14
- YjUzOTc0MTNlZjliZmZhN2Q2NWMyNzliYTk1MGMyMTJhYTliMDE5M2I1ZDdh
15
- NTRmMWNlYzEyMDhiOWNhYzY0YmFhZGFiZWQxNjI0ZmRjMWE3Nzk=
2
+ SHA1:
3
+ metadata.gz: 9f46ec6236e6ad3bcfc8e36c2825e34ba8c55cf5
4
+ data.tar.gz: cdfc85da172a8f7dc4c9d2576d242d5712d0dc8d
5
+ SHA512:
6
+ metadata.gz: 35ea7f5d3aecf567b4cf58b1b333430fc72a52a773d7b78b0249390a8d8937b8e11c3ea1504daa5b9ac6ae00ed01d69defd82fd3b3f56b93fd2a2db034295cd5
7
+ data.tar.gz: eca3055ef3b4525c10d2aeeb9040a836dd5911cd783624eb716192ca4a96caa4aea85e1bf2e551b329d34fab0e70824dbcfbd0bf759b23175b4a0e36a5c23845
data/README ADDED
@@ -0,0 +1 @@
1
+ README.md
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.4.1
@@ -2,12 +2,13 @@ require 'rack'
2
2
 
3
3
  module Rack
4
4
  module Throttle
5
- autoload :Limiter, 'rack/throttle/limiter'
6
- autoload :Interval, 'rack/throttle/interval'
7
- autoload :TimeWindow, 'rack/throttle/time_window'
8
- autoload :Daily, 'rack/throttle/daily'
9
- autoload :Hourly, 'rack/throttle/hourly'
10
- autoload :Minute, 'rack/throttle/minute'
11
- autoload :VERSION, 'rack/throttle/version'
5
+ autoload :Limiter, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/limiter'
6
+ autoload :Interval, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/interval'
7
+ autoload :TimeWindow, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/time_window'
8
+ autoload :Daily, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/daily'
9
+ autoload :Hourly, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/hourly'
10
+ autoload :Minute, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/minute'
11
+ autoload :Second, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/second'
12
+ autoload :VERSION, ::File.expand_path(::File.dirname(__FILE__)) + '/throttle/version'
12
13
  end
13
14
  end
@@ -21,6 +21,7 @@ module Rack; module Throttle
21
21
  # @option options [String] :key_prefix (nil)
22
22
  # @option options [Integer] :code (403)
23
23
  # @option options [String] :message ("Rate Limit Exceeded")
24
+ # @option options [String] :type ("text/plain; charset=utf-8")
24
25
  def initialize(app, options = {})
25
26
  @app, @options = app, options
26
27
  end
@@ -189,8 +190,12 @@ module Rack; module Throttle
189
190
  # @param [Hash{String => String}] headers
190
191
  # @return [Array(Integer, Hash, #each)]
191
192
  def http_error(code, message = nil, headers = {})
192
- [code, {'Content-Type' => 'text/plain; charset=utf-8'}.merge(headers),
193
- [http_status(code), (message.nil? ? "\n" : " (#{message})\n")]]
193
+ contentType = 'text/plain; charset=utf-8'
194
+ if options[:type]
195
+ contentType = options[:type]
196
+ end
197
+ [code, {'Content-Type' => contentType}.merge(headers),
198
+ [message]]
194
199
  end
195
200
 
196
201
  ##
@@ -12,7 +12,7 @@ module Rack; module Throttle
12
12
  # @example Allowing up to 60 requests/minute
13
13
  # use Rack::Throttle::Minute
14
14
  #
15
- # @example Allowing up to 100 requests per hour
15
+ # @example Allowing up to 100 requests per minute
16
16
  # use Rack::Throttle::Minute, :max => 100
17
17
  #
18
18
  class Minute < TimeWindow
@@ -26,7 +26,7 @@ module Rack; module Throttle
26
26
 
27
27
  ##
28
28
  def max_per_minute
29
- @max_per_hour ||= options[:max_per_minute] || options[:max] || 60
29
+ @max_per_minute ||= options[:max_per_minute] || options[:max] || 60
30
30
  end
31
31
 
32
32
  alias_method :max_per_window, :max_per_minute
@@ -0,0 +1,42 @@
1
+ module Rack; module Throttle
2
+ ##
3
+ # This rate limiter strategy throttles the application by defining a
4
+ # maximum number of allowed HTTP requests per second (by default, 1
5
+ # request per second.
6
+ #
7
+ # Note that this strategy doesn't use a sliding time window, but rather
8
+ # tracks requests per distinct second. This means that the throttling
9
+ # counter is reset every second.
10
+ #
11
+ # @example Allowing up to 1 request/second
12
+ # use Rack::Throttle::Second
13
+ #
14
+ # @example Allowing up to 100 requests per second
15
+ # use Rack::Throttle::Second, :max => 100
16
+ #
17
+ class Second < TimeWindow
18
+ ##
19
+ # @param [#call] app
20
+ # @param [Hash{Symbol => Object}] options
21
+ # @option options [Integer] :max (1)
22
+ def initialize(app, options = {})
23
+ super
24
+ end
25
+
26
+ ##
27
+ def max_per_second
28
+ @max_per_second ||= options[:max_per_second] || options[:max] || 1
29
+ end
30
+
31
+ alias_method :max_per_window, :max_per_second
32
+
33
+ protected
34
+
35
+ ##
36
+ # @param [Rack::Request] request
37
+ # @return [String]
38
+ def cache_key(request)
39
+ [super, Time.now.strftime('%Y-%m-%dT%H:%S')].join(':')
40
+ end
41
+ end
42
+ end; end
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-throttle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arto Bendiken
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-14 00:00:00.000000000 Z
11
+ date: 2016-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: rack-test
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -25,33 +53,33 @@ dependencies:
25
53
  - !ruby/object:Gem::Version
26
54
  version: 0.5.3
27
55
  - !ruby/object:Gem::Dependency
28
- name: rspec
56
+ name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - '='
59
+ - - ">="
32
60
  - !ruby/object:Gem::Version
33
- version: 1.3.0
61
+ version: '0'
34
62
  type: :development
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - '='
66
+ - - ">="
39
67
  - !ruby/object:Gem::Version
40
- version: 1.3.0
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
- name: yard
70
+ name: rspec
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
- - - ! '>='
73
+ - - '='
46
74
  - !ruby/object:Gem::Version
47
- version: 0.5.5
75
+ version: 1.3.0
48
76
  type: :development
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
- - - ! '>='
80
+ - - '='
53
81
  - !ruby/object:Gem::Version
54
- version: 0.5.5
82
+ version: 1.3.0
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: timecop
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -67,19 +95,19 @@ dependencies:
67
95
  - !ruby/object:Gem::Version
68
96
  version: 0.3.4
69
97
  - !ruby/object:Gem::Dependency
70
- name: rack
98
+ name: yard
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
- - - ! '>='
101
+ - - ">="
74
102
  - !ruby/object:Gem::Version
75
- version: 1.0.0
76
- type: :runtime
103
+ version: 0.5.5
104
+ type: :development
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
- - - ! '>='
108
+ - - ">="
81
109
  - !ruby/object:Gem::Version
82
- version: 1.0.0
110
+ version: 0.5.5
83
111
  description: Rack middleware for rate-limiting incoming HTTP requests.
84
112
  email: arto@bendiken.net
85
113
  executables: []
@@ -90,14 +118,15 @@ files:
90
118
  - README
91
119
  - UNLICENSE
92
120
  - VERSION
121
+ - lib/rack/throttle.rb
93
122
  - lib/rack/throttle/daily.rb
94
123
  - lib/rack/throttle/hourly.rb
95
124
  - lib/rack/throttle/interval.rb
96
125
  - lib/rack/throttle/limiter.rb
97
126
  - lib/rack/throttle/minute.rb
127
+ - lib/rack/throttle/second.rb
98
128
  - lib/rack/throttle/time_window.rb
99
129
  - lib/rack/throttle/version.rb
100
- - lib/rack/throttle.rb
101
130
  homepage: https://github.com/bendiken/rack-throttle
102
131
  licenses:
103
132
  - Public Domain
@@ -108,19 +137,18 @@ require_paths:
108
137
  - lib
109
138
  required_ruby_version: !ruby/object:Gem::Requirement
110
139
  requirements:
111
- - - ! '>='
140
+ - - ">="
112
141
  - !ruby/object:Gem::Version
113
142
  version: 1.8.2
114
143
  required_rubygems_version: !ruby/object:Gem::Requirement
115
144
  requirements:
116
- - - ! '>='
145
+ - - ">="
117
146
  - !ruby/object:Gem::Version
118
147
  version: '0'
119
148
  requirements: []
120
149
  rubyforge_project:
121
- rubygems_version: 2.0.3
150
+ rubygems_version: 2.5.1
122
151
  signing_key:
123
152
  specification_version: 4
124
153
  summary: HTTP request rate limiter for Rack applications.
125
154
  test_files: []
126
- has_rdoc: false
data/README DELETED
@@ -1,223 +0,0 @@
1
- HTTP Request Rate Limiter for Rack Applications
2
- ===============================================
3
-
4
- This is [Rack][] middleware that provides logic for rate-limiting incoming
5
- HTTP requests to Rack applications. You can use `Rack::Throttle` with any
6
- Ruby web framework based on Rack, including with Ruby on Rails and with
7
- Sinatra.
8
-
9
- * <https://github.com/bendiken/rack-throttle>
10
-
11
- Features
12
- --------
13
-
14
- * Throttles a Rack application by enforcing a minimum time interval between
15
- subsequent HTTP requests from a particular client, as well as by defining
16
- a maximum number of allowed HTTP requests per a given time period (per minute,
17
- hourly, or daily).
18
- * Compatible with any Rack application and any Rack-based framework.
19
- * Stores rate-limiting counters in any key/value store implementation that
20
- responds to `#[]`/`#[]=` (like Ruby's hashes) or to `#get`/`#set` (like
21
- memcached or Redis).
22
- * Compatible with the [gdbm][] binding included in Ruby's standard library.
23
- * Compatible with the [memcached][], [memcache-client][], [memcache][] and
24
- [redis][] gems.
25
- * Compatible with [Heroku][]'s [memcached add-on][Heroku memcache]
26
- (currently available as a free beta service).
27
-
28
- Examples
29
- --------
30
-
31
- ### Adding throttling to a Rails application
32
-
33
- # config/application.rb
34
- require 'rack/throttle'
35
-
36
- class Application < Rails::Application
37
- config.middleware.use Rack::Throttle::Interval
38
- end
39
-
40
- ### Adding throttling to a Sinatra application
41
-
42
- #!/usr/bin/env ruby -rubygems
43
- require 'sinatra'
44
- require 'rack/throttle'
45
-
46
- use Rack::Throttle::Interval
47
-
48
- get('/hello') { "Hello, world!\n" }
49
-
50
- ### Adding throttling to a Rackup application
51
-
52
- #!/usr/bin/env rackup
53
- require 'rack/throttle'
54
-
55
- use Rack::Throttle::Interval
56
-
57
- run lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, world!\n"] }
58
-
59
- ### Enforcing a minimum 3-second interval between requests
60
-
61
- use Rack::Throttle::Interval, :min => 3.0
62
-
63
- ### Allowing a maximum of 60 requests per minute
64
-
65
- use Rack::Throttle::Minute, :max => 60
66
-
67
- ### Allowing a maximum of 100 requests per hour
68
-
69
- use Rack::Throttle::Hourly, :max => 100
70
-
71
- ### Allowing a maximum of 1,000 requests per day
72
-
73
- use Rack::Throttle::Daily, :max => 1000
74
-
75
- ### Combining various throttling constraints into one overall policy
76
-
77
- use Rack::Throttle::Daily, :max => 1000 # requests
78
- use Rack::Throttle::Hourly, :max => 100 # requests
79
- use Rack::Throttle::Minute, :max => 60 # requests
80
- use Rack::Throttle::Interval, :min => 3.0 # seconds
81
-
82
- ### Storing the rate-limiting counters in a GDBM database
83
-
84
- require 'gdbm'
85
-
86
- use Rack::Throttle::Interval, :cache => GDBM.new('tmp/throttle.db')
87
-
88
- ### Storing the rate-limiting counters on a Memcached server
89
-
90
- require 'memcached'
91
-
92
- use Rack::Throttle::Interval, :cache => Memcached.new, :key_prefix => :throttle
93
-
94
- ### Storing the rate-limiting counters on a Redis server
95
-
96
- require 'redis'
97
-
98
- use Rack::Throttle::Interval, :cache => Redis.new, :key_prefix => :throttle
99
-
100
- Throttling Strategies
101
- ---------------------
102
-
103
- `Rack::Throttle` supports three built-in throttling strategies:
104
-
105
- * `Rack::Throttle::Interval`: Throttles the application by enforcing a
106
- minimum interval (by default, 1 second) between subsequent HTTP requests.
107
- * `Rack::Throttle::Hourly`: Throttles the application by defining a
108
- maximum number of allowed HTTP requests per hour (by default, 3,600
109
- requests per 60 minutes, which works out to an average of 1 request per
110
- second).
111
- * `Rack::Throttle::Daily`: Throttles the application by defining a
112
- maximum number of allowed HTTP requests per day (by default, 86,400
113
- requests per 24 hours, which works out to an average of 1 request per
114
- second).
115
-
116
- You can fully customize the implementation details of any of these strategies
117
- by simply subclassing one of the aforementioned default implementations.
118
- And, of course, should your application-specific requirements be
119
- significantly more complex than what we've provided for, you can also define
120
- entirely new kinds of throttling strategies by subclassing the
121
- `Rack::Throttle::Limiter` base class directly.
122
-
123
- HTTP Client Identification
124
- --------------------------
125
-
126
- The rate-limiting counters stored and maintained by `Rack::Throttle` are
127
- keyed to unique HTTP clients.
128
-
129
- By default, HTTP clients are uniquely identified by their IP address as
130
- returned by `Rack::Request#ip`. If you wish to instead use a more granular,
131
- application-specific identifier such as a session key or a user account
132
- name, you need only subclass a throttling strategy implementation and
133
- override the `#client_identifier` method.
134
-
135
- HTTP Response Codes and Headers
136
- -------------------------------
137
-
138
- ### 403 Forbidden (Rate Limit Exceeded)
139
-
140
- When a client exceeds their rate limit, `Rack::Throttle` by default returns
141
- a "403 Forbidden" response with an associated "Rate Limit Exceeded" message
142
- in the response body.
143
-
144
- An HTTP 403 response means that the server understood the request, but is
145
- refusing to respond to it and an accompanying message will explain why.
146
- This indicates an error on the client's part in exceeding the rate limits
147
- outlined in the acceptable use policy for the site, service, or API.
148
-
149
- ### 503 Service Unavailable (Rate Limit Exceeded)
150
-
151
- However, there exists a widespread practice of instead returning a "503
152
- Service Unavailable" response when a client exceeds the set rate limits.
153
- This is technically dubious because it indicates an error on the server's
154
- part, which is certainly not the case with rate limiting - it was the client
155
- that committed the oops, not the server.
156
-
157
- An HTTP 503 response would be correct in situations where the server was
158
- genuinely overloaded and couldn't handle more requests, but for rate
159
- limiting an HTTP 403 response is more appropriate. Nonetheless, if you think
160
- otherwise, `Rack::Throttle` does allow you to override the returned HTTP
161
- status code by passing in a `:code => 503` option when constructing a
162
- `Rack::Throttle::Limiter` instance.
163
-
164
- Dependencies
165
- ------------
166
-
167
- * [Rack](http://rubygems.org/gems/rack) (>= 1.0.0)
168
-
169
- Installation
170
- ------------
171
-
172
- The recommended installation method is via [RubyGems](http://rubygems.org/).
173
- To install the latest official release of the gem, do:
174
-
175
- % [sudo] gem install rack-throttle
176
-
177
- Authors
178
- -------
179
-
180
- * [Arto Bendiken](https://gratipay.com/bendiken) - <http://ar.to/>
181
-
182
- Contributors
183
- ------------
184
-
185
- * [Brendon Murphy](https://github.com/bemurphy)
186
- * [Hendrik Kleinwaechter](https://github.com/hendricius)
187
- * [Karel Minarik](https://github.com/karmi)
188
- * [Keita Urashima](https://github.com/ursm)
189
- * [Leonid Beder](https://github.com/lbeder)
190
- * [TJ Singleton](https://github.com/tjsingleton)
191
- * [Winfield Peterson](https://github.com/wpeterson)
192
-
193
- Contributing
194
- ------------
195
-
196
- * Do your best to adhere to the existing coding conventions and idioms.
197
- * Don't use hard tabs, and don't leave trailing whitespace on any line.
198
- Before committing, run `git diff --check` to make sure of this.
199
- * Do document every method you add using [YARD][] annotations. Read the
200
- [tutorial][YARD-GS] or just look at the existing code for examples.
201
- * Don't touch the gemspec or `VERSION` files. If you need to change them,
202
- do so on your private branch only.
203
- * Do feel free to add yourself to the `CREDITS` file and the
204
- corresponding list in the the `README`. Alphabetical order applies.
205
- * Don't touch the `AUTHORS` file. If your contributions are significant
206
- enough, be assured we will eventually add you in there.
207
-
208
- License
209
- -------
210
-
211
- This is free and unencumbered public domain software. For more information,
212
- see <http://unlicense.org/> or the accompanying `UNLICENSE` file.
213
-
214
- [Rack]: http://rack.rubyforge.org/
215
- [gdbm]: http://ruby-doc.org/stdlib/libdoc/gdbm/rdoc/classes/GDBM.html
216
- [memcached]: http://rubygems.org/gems/memcached
217
- [memcache-client]: http://rubygems.org/gems/memcache-client
218
- [memcache]: http://rubygems.org/gems/memcache
219
- [redis]: http://rubygems.org/gems/redis
220
- [Heroku]: http://heroku.com/
221
- [Heroku memcache]: http://docs.heroku.com/memcache
222
- [YARD]: http://yardoc.org/
223
- [YARD-GS]: http://rubydoc.info/docs/yard/file/docs/GettingStarted.md