viximo-rack-throttle 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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