rack-throttle 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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