viximo-rack-throttle 0.4.0 → 0.5.0

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.
data/README CHANGED
@@ -139,32 +139,18 @@ override the `#client_identifier` method.
139
139
 
140
140
  HTTP Response Codes and Headers
141
141
  -------------------------------
142
+ ### 429 Too Many Requests
143
+ In the past various status codes has been used to indicate over-use.
142
144
 
143
- ### 403 Forbidden (Rate Limit Exceeded)
145
+ In 2012, the IETF standardized on a new response status 429 (Too Many Requests)
146
+ [RFC6585].
144
147
 
145
148
  When a client exceeds their rate limit, `Rack::Throttle` by default returns
146
- a "403 Forbidden" response with an associated "Rate Limit Exceeded" message
149
+ a 429 (Too Many Requests) header with an associated "Rate Limit Exceeded" message
147
150
  in the response body.
148
151
 
149
- An HTTP 403 response means that the server understood the request, but is
150
- refusing to respond to it and an accompanying message will explain why.
151
- This indicates an error on the client's part in exceeding the rate limits
152
- outlined in the acceptable use policy for the site, service, or API.
153
-
154
- ### 503 Service Unavailable (Rate Limit Exceeded)
155
-
156
- However, there exists a widespread practice of instead returning a "503
157
- Service Unavailable" response when a client exceeds the set rate limits.
158
- This is technically dubious because it indicates an error on the server's
159
- part, which is certainly not the case with rate limiting - it was the client
160
- that committed the oops, not the server.
161
-
162
- An HTTP 503 response would be correct in situations where the server was
163
- genuinely overloaded and couldn't handle more requests, but for rate
164
- limiting an HTTP 403 response is more appropriate. Nonetheless, if you think
165
- otherwise, `Rack::Throttle` does allow you to override the returned HTTP
166
- status code by passing in a `:code => 503` option when constructing a
167
- `Rack::Throttle::Limiter` instance.
152
+ The status code can be overridden by passing in `:code => 403` option when
153
+ constructing a `Rack::Throttle::Limiter` instance.
168
154
 
169
155
  Documentation
170
156
  -------------
@@ -221,3 +207,4 @@ information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
221
207
  [redis]: http://rubygems.org/gems/redis
222
208
  [Heroku]: http://heroku.com/
223
209
  [Heroku memcache]: http://docs.heroku.com/memcache
210
+ [RFC6585]: http://tools.ietf.org/html/rfc6585
@@ -32,6 +32,10 @@ module Rack; module Throttle
32
32
 
33
33
  alias_method :max_per_window, :max_per_day
34
34
 
35
+ def retry_after
36
+ "86400" # simplification, because the strategy is not sliding
37
+ end
38
+
35
39
  protected
36
40
 
37
41
  ##
@@ -41,4 +45,4 @@ module Rack; module Throttle
41
45
  [super, Time.now.strftime('%Y-%m-%d')].join(':')
42
46
  end
43
47
  end
44
- end; end
48
+ end; end
@@ -32,6 +32,10 @@ module Rack; module Throttle
32
32
 
33
33
  alias_method :max_per_window, :max_per_hour
34
34
 
35
+ def retry_after
36
+ "3600" # simplification, because the strategy is not sliding
37
+ end
38
+
35
39
  protected
36
40
 
37
41
  ##
@@ -27,11 +27,11 @@ module Rack; module Throttle
27
27
  # @param [Rack::Request] request
28
28
  # @return [Boolean]
29
29
  def allowed?(request)
30
- t1 = request_start_time(request)
31
- t0 = cache_get(key = cache_key(request)) rescue nil
32
- allowed = !t0 || (dt = t1 - t0.to_f) >= minimum_interval
30
+ start_time = request_start_time(request)
31
+ last_call_time = cache_get(key = cache_key(request)) rescue nil
32
+ allowed = !last_call_time || (dt = start_time - last_call_time.to_f) >= minimum_interval
33
33
  begin
34
- cache_set(key, t1)
34
+ cache_set(key, start_time)
35
35
  allowed
36
36
  rescue => e
37
37
  # If an error occurred while trying to update the timestamp stored
@@ -10,16 +10,20 @@ module Rack; module Throttle
10
10
  # end
11
11
  #
12
12
  class Limiter
13
+
13
14
  attr_reader :app
14
15
  attr_reader :options
15
-
16
+
17
+ CODE = 429 # http://tools.ietf.org/html/rfc6585
18
+ MESSAGE = "Rate Limit Exceeded"
19
+
16
20
  ##
17
21
  # @param [#call] app
18
22
  # @param [Hash{Symbol => Object}] options
19
23
  # @option options [String] :cache (Hash.new)
20
24
  # @option options [String] :key (nil)
21
25
  # @option options [String] :key_prefix (nil)
22
- # @option options [Integer] :code (403)
26
+ # @option options [Integer] :code (429)
23
27
  # @option options [String] :message ("Rate Limit Exceeded")
24
28
  def initialize(app, options = {})
25
29
  @app, @options = app, options
@@ -177,7 +181,7 @@ module Rack; module Throttle
177
181
  def rate_limit_exceeded(request)
178
182
  options[:rate_limit_exceeded_callback].call(request) if options[:rate_limit_exceeded_callback]
179
183
  headers = respond_to?(:retry_after) ? {'Retry-After' => retry_after.to_f.ceil.to_s} : {}
180
- http_error(options[:code] || 403, options[:message] || 'Rate Limit Exceeded', headers)
184
+ http_error(options[:code] || CODE, options[:message] || MESSAGE, headers)
181
185
  end
182
186
 
183
187
  ##
@@ -28,6 +28,10 @@ module Rack; module Throttle
28
28
  def max_per_minute
29
29
  @max_per_hour ||= options[:max_per_minute] || options[:max] || 60
30
30
  end
31
+
32
+ def retry_after
33
+ "60" # simplification, because the strategy is not sliding
34
+ end
31
35
 
32
36
  alias_method :max_per_window, :max_per_minute
33
37
 
@@ -1,7 +1,7 @@
1
1
  module Rack; module Throttle
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 4
4
+ MINOR = 5
5
5
  TINY = 0
6
6
  EXTRA = nil
7
7
 
metadata CHANGED
@@ -1,113 +1,103 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: viximo-rack-throttle
3
- version: !ruby/object:Gem::Version
4
- hash: 15
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 4
9
- - 0
10
- version: 0.4.0
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Arto Bendiken
14
9
  - Brendon Murphy
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2011-10-31 00:00:00 -04:00
20
- default_executable:
21
- dependencies:
22
- - !ruby/object:Gem::Dependency
13
+ date: 2012-05-14 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
23
16
  name: rack-test
24
- prerelease: false
25
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
26
18
  none: false
27
- requirements:
28
- - - "="
29
- - !ruby/object:Gem::Version
30
- hash: 13
31
- segments:
32
- - 0
33
- - 5
34
- - 3
19
+ requirements:
20
+ - - '='
21
+ - !ruby/object:Gem::Version
35
22
  version: 0.5.3
36
23
  type: :development
37
- version_requirements: *id001
38
- - !ruby/object:Gem::Dependency
39
- name: rspec
40
24
  prerelease: false
41
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - '='
29
+ - !ruby/object:Gem::Version
30
+ version: 0.5.3
31
+ - !ruby/object:Gem::Dependency
32
+ name: rspec
33
+ requirement: !ruby/object:Gem::Requirement
42
34
  none: false
43
- requirements:
44
- - - "="
45
- - !ruby/object:Gem::Version
46
- hash: 27
47
- segments:
48
- - 1
49
- - 3
50
- - 0
35
+ requirements:
36
+ - - '='
37
+ - !ruby/object:Gem::Version
51
38
  version: 1.3.0
52
39
  type: :development
53
- version_requirements: *id002
54
- - !ruby/object:Gem::Dependency
55
- name: yard
56
40
  prerelease: false
57
- requirement: &id003 !ruby/object:Gem::Requirement
41
+ version_requirements: !ruby/object:Gem::Requirement
58
42
  none: false
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- hash: 1
63
- segments:
64
- - 0
65
- - 5
66
- - 5
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.3.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: yard
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
67
54
  version: 0.5.5
68
55
  type: :development
69
- version_requirements: *id003
70
- - !ruby/object:Gem::Dependency
71
- name: timecop
72
56
  prerelease: false
73
- requirement: &id004 !ruby/object:Gem::Requirement
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: 0.5.5
63
+ - !ruby/object:Gem::Dependency
64
+ name: timecop
65
+ requirement: !ruby/object:Gem::Requirement
74
66
  none: false
75
- requirements:
76
- - - "="
77
- - !ruby/object:Gem::Version
78
- hash: 27
79
- segments:
80
- - 0
81
- - 3
82
- - 4
67
+ requirements:
68
+ - - '='
69
+ - !ruby/object:Gem::Version
83
70
  version: 0.3.4
84
71
  type: :development
85
- version_requirements: *id004
86
- - !ruby/object:Gem::Dependency
87
- name: rack
88
72
  prerelease: false
89
- requirement: &id005 !ruby/object:Gem::Requirement
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - '='
77
+ - !ruby/object:Gem::Version
78
+ version: 0.3.4
79
+ - !ruby/object:Gem::Dependency
80
+ name: rack
81
+ requirement: !ruby/object:Gem::Requirement
90
82
  none: false
91
- requirements:
92
- - - ">="
93
- - !ruby/object:Gem::Version
94
- hash: 23
95
- segments:
96
- - 1
97
- - 0
98
- - 0
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
99
86
  version: 1.0.0
100
87
  type: :runtime
101
- version_requirements: *id005
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: 1.0.0
102
95
  description: Rack middleware for rate-limiting incoming HTTP requests.
103
96
  email: arto.bendiken@gmail.com
104
97
  executables: []
105
-
106
98
  extensions: []
107
-
108
99
  extra_rdoc_files: []
109
-
110
- files:
100
+ files:
111
101
  - AUTHORS
112
102
  - README
113
103
  - UNLICENSE
@@ -119,41 +109,30 @@ files:
119
109
  - lib/rack/throttle/time_window.rb
120
110
  - lib/rack/throttle/version.rb
121
111
  - lib/rack/throttle.rb
122
- has_rdoc: false
123
112
  homepage: http://github.com/Viximo/rack-throttle
124
- licenses:
113
+ licenses:
125
114
  - Public Domain
126
115
  post_install_message:
127
116
  rdoc_options: []
128
-
129
- require_paths:
117
+ require_paths:
130
118
  - lib
131
- required_ruby_version: !ruby/object:Gem::Requirement
119
+ required_ruby_version: !ruby/object:Gem::Requirement
132
120
  none: false
133
- requirements:
134
- - - ">="
135
- - !ruby/object:Gem::Version
136
- hash: 51
137
- segments:
138
- - 1
139
- - 8
140
- - 2
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
141
124
  version: 1.8.2
142
- required_rubygems_version: !ruby/object:Gem::Requirement
125
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
126
  none: false
144
- requirements:
145
- - - ">="
146
- - !ruby/object:Gem::Version
147
- hash: 3
148
- segments:
149
- - 0
150
- version: "0"
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
151
131
  requirements: []
152
-
153
132
  rubyforge_project: datagraph
154
- rubygems_version: 1.5.3
133
+ rubygems_version: 1.8.21
155
134
  signing_key:
156
135
  specification_version: 3
157
136
  summary: HTTP request rate limiter for Rack applications.
158
137
  test_files: []
159
-
138
+ has_rdoc: false