improved-rack-throttle 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dea077855e9d5f1e7aa8126af311c58f518e2abf
4
+ data.tar.gz: d1c0ce949e3a7152adfb1b9b6ae96896021d5e81
5
+ SHA512:
6
+ metadata.gz: 77a62c9ad00ee3aff04a413e5e186a261cd925c9b46e281dd167604fee5b3df2451daf4eb775f1c3b94a4b1e1fb16feddd35828763ed33666dc62df7c5bfc6cb
7
+ data.tar.gz: ab2f078f3380a13826fbb30f47292540ae59c8cf3269f1fa4ce051825962574d7d9e6021709058381dabb7035cd610b4ce05d2575e57f196292abb4aa00bde8f
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.8.7"
4
+ - "1.9.2"
5
+ - "1.9.3"
6
+ - "2.0.0"
7
+ - "2.1.3"
8
+ # uncomment this line if your project needs to run something other than `rake`:
9
+ # script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -3,10 +3,11 @@ source "http://rubygems.org"
3
3
  gem "rack", ">= 1.0.0"
4
4
 
5
5
  group :development, :test do
6
- gem 'timecop', '~> 0.5.2'
7
- gem 'rack-test', '~> 0.6.2'
8
- gem 'rspec', '~> 2.11.0'
9
- gem 'yard' , '>= 0.5.5'
6
+ gem 'timecop', "<= 0.6.2.2"
7
+ gem 'rack-test'
8
+ gem 'rspec'
9
+ gem 'yard'
10
+ gem "simplecov", :require => false
10
11
  gem 'redcarpet'
11
12
  gem 'rake'
12
13
  gem 'jeweler'
@@ -1,31 +1,40 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- diff-lcs (1.1.3)
4
+ diff-lcs (1.2.5)
5
5
  git (1.2.5)
6
6
  jeweler (1.8.4)
7
7
  bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
10
  rdoc
11
- json (1.7.6)
12
- rack (1.4.4)
11
+ json (1.8.0)
12
+ multi_json (1.7.6)
13
+ rack (1.5.2)
13
14
  rack-test (0.6.2)
14
15
  rack (>= 1.0)
15
- rake (10.0.3)
16
- rdoc (3.12)
16
+ rake (10.0.4)
17
+ rdoc (4.0.1)
17
18
  json (~> 1.4)
18
- redcarpet (2.2.2)
19
- rspec (2.11.0)
20
- rspec-core (~> 2.11.0)
21
- rspec-expectations (~> 2.11.0)
22
- rspec-mocks (~> 2.11.0)
23
- rspec-core (2.11.1)
24
- rspec-expectations (2.11.3)
25
- diff-lcs (~> 1.1.3)
26
- rspec-mocks (2.11.3)
27
- timecop (0.5.9.1)
28
- yard (0.8.3)
19
+ redcarpet (2.3.0)
20
+ rspec (3.0.0)
21
+ rspec-core (~> 3.0.0)
22
+ rspec-expectations (~> 3.0.0)
23
+ rspec-mocks (~> 3.0.0)
24
+ rspec-core (3.0.1)
25
+ rspec-support (~> 3.0.0)
26
+ rspec-expectations (3.0.1)
27
+ diff-lcs (>= 1.2.0, < 2.0)
28
+ rspec-support (~> 3.0.0)
29
+ rspec-mocks (3.0.1)
30
+ rspec-support (~> 3.0.0)
31
+ rspec-support (3.0.0)
32
+ simplecov (0.7.1)
33
+ multi_json (~> 1.0)
34
+ simplecov-html (~> 0.7.1)
35
+ simplecov-html (0.7.1)
36
+ timecop (0.6.1)
37
+ yard (0.8.6.1)
29
38
 
30
39
  PLATFORMS
31
40
  ruby
@@ -33,9 +42,10 @@ PLATFORMS
33
42
  DEPENDENCIES
34
43
  jeweler
35
44
  rack (>= 1.0.0)
36
- rack-test (~> 0.6.2)
45
+ rack-test
37
46
  rake
38
47
  redcarpet
39
- rspec (~> 2.11.0)
40
- timecop (~> 0.5.2)
41
- yard (>= 0.5.5)
48
+ rspec
49
+ simplecov
50
+ timecop (<= 0.6.2.2)
51
+ yard
data/README.md CHANGED
@@ -3,6 +3,7 @@ HTTP Request Rate Limiter for Rack Applications
3
3
 
4
4
  [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/bensomers/improved-rack-throttle)
5
5
  [![Dependency Status](https://gemnasium.com/bensomers/improved-rack-throttle.png)](https://gemnasium.com/bensomers/improved-rack-throttle)
6
+ [![Build Status](https://travis-ci.org/bensomers/improved-rack-throttle.png?branch=master)](https://travis-ci.org/bensomers/improved-rack-throttle)
6
7
 
7
8
  This is a [Rack][] middleware that provides logic for rate-limiting incoming
8
9
  HTTP requests to Rack applications. You can use `Rack::Throttle` with any
@@ -37,7 +38,7 @@ Examples
37
38
 
38
39
  # config/application.rb
39
40
  require 'rack/throttle'
40
-
41
+
41
42
  class Application < Rails::Application
42
43
  config.middleware.use Rack::Throttle::Interval
43
44
  end
@@ -47,18 +48,18 @@ Examples
47
48
  #!/usr/bin/env ruby -rubygems
48
49
  require 'sinatra'
49
50
  require 'rack/throttle'
50
-
51
+
51
52
  use Rack::Throttle::Interval
52
-
53
+
53
54
  get('/hello') { "Hello, world!\n" }
54
55
 
55
56
  ### Adding throttling to a Rackup application
56
57
 
57
58
  #!/usr/bin/env rackup
58
59
  require 'rack/throttle'
59
-
60
+
60
61
  use Rack::Throttle::Interval
61
-
62
+
62
63
  run lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, world!\n"] }
63
64
 
64
65
  ### Enforcing a minimum 3-second interval between requests
@@ -86,19 +87,19 @@ Examples
86
87
  ### Storing the rate-limiting counters in a GDBM database
87
88
 
88
89
  require 'gdbm'
89
-
90
+
90
91
  use Rack::Throttle::Interval, :cache => GDBM.new('tmp/throttle.db')
91
92
 
92
93
  ### Storing the rate-limiting counters on a Memcached server
93
94
 
94
95
  require 'memcached'
95
-
96
+
96
97
  use Rack::Throttle::Interval, :cache => Memcached.new, :key_prefix => :throttle
97
98
 
98
99
  ### Storing the rate-limiting counters on a Redis server
99
100
 
100
101
  require 'redis'
101
-
102
+
102
103
  use Rack::Throttle::Interval, :cache => Redis.new, :key_prefix => :throttle
103
104
 
104
105
  ### Scoping the rate-limit to a specific path and method
@@ -188,8 +189,6 @@ status code by passing in a `:code => 503` option when constructing a
188
189
 
189
190
  Documentation
190
191
  -------------
191
- UNDER DEVELOPMENT
192
-
193
192
  <http://rubydoc.info/gems/improved-rack-throttle>
194
193
 
195
194
  * {Rack::Throttle}
@@ -229,7 +228,7 @@ as follows:
229
228
 
230
229
  Authors
231
230
  -------
232
- * [Ben Somers](mailto:somers.ben@gmail.com) - <http://www.somanyrobots.com>
231
+ * [Ben Somers](mailto:somers.ben@gmail.com) - <http://www.github.com/bensomers>
233
232
  * [Arto Bendiken](mailto:arto.bendiken@gmail.com) - <http://ar.to/>
234
233
  * [Brendon Murphy](mailto:disposable.20.xternal@spamourmet.com>) - <http://www.techfreak.net/>
235
234
 
data/Rakefile CHANGED
@@ -28,8 +28,6 @@ Jeweler::Tasks.new do |gem|
28
28
  end
29
29
  Jeweler::RubygemsDotOrgTasks.new
30
30
 
31
- task :default => :spec
32
-
33
31
  require 'rdoc/task'
34
32
  Rake::RDocTask.new do |rdoc|
35
33
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
@@ -39,3 +37,7 @@ Rake::RDocTask.new do |rdoc|
39
37
  rdoc.rdoc_files.include('README*')
40
38
  rdoc.rdoc_files.include('lib/**/*.rb')
41
39
  end
40
+
41
+ require 'rspec/core/rake_task'
42
+ RSpec::Core::RakeTask.new(:spec)
43
+ task :default => :spec
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "improved-rack-throttle"
8
- s.version = "0.7.1"
8
+ s.version = "0.8.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben Somers", "Arto Bendiken", "Brendon Murphy"]
12
- s.date = "2013-05-09"
12
+ s.date = "2014-09-22"
13
13
  s.description = "Rack middleware for rate-limiting incoming HTTP requests."
14
14
  s.email = "somers.ben@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
17
17
  ]
18
18
  s.files = [
19
19
  ".document",
20
+ ".travis.yml",
20
21
  "Gemfile",
21
22
  "Gemfile.lock",
22
23
  "README.md",
@@ -55,37 +56,40 @@ Gem::Specification.new do |s|
55
56
  s.homepage = "http://github.com/bensomers/improved-rack-throttle"
56
57
  s.licenses = ["Public Domain"]
57
58
  s.require_paths = ["lib"]
58
- s.rubygems_version = "1.8.25"
59
+ s.rubygems_version = "2.0.3"
59
60
  s.summary = "HTTP request rate limiter for Rack applications."
60
61
 
61
62
  if s.respond_to? :specification_version then
62
- s.specification_version = 3
63
+ s.specification_version = 4
63
64
 
64
65
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
65
66
  s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
66
- s.add_development_dependency(%q<timecop>, ["~> 0.5.2"])
67
- s.add_development_dependency(%q<rack-test>, ["~> 0.6.2"])
68
- s.add_development_dependency(%q<rspec>, ["~> 2.11.0"])
69
- s.add_development_dependency(%q<yard>, [">= 0.5.5"])
67
+ s.add_development_dependency(%q<timecop>, ["<= 0.6.2.2"])
68
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
69
+ s.add_development_dependency(%q<rspec>, [">= 0"])
70
+ s.add_development_dependency(%q<yard>, [">= 0"])
71
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
70
72
  s.add_development_dependency(%q<redcarpet>, [">= 0"])
71
73
  s.add_development_dependency(%q<rake>, [">= 0"])
72
74
  s.add_development_dependency(%q<jeweler>, [">= 0"])
73
75
  else
74
76
  s.add_dependency(%q<rack>, [">= 1.0.0"])
75
- s.add_dependency(%q<timecop>, ["~> 0.5.2"])
76
- s.add_dependency(%q<rack-test>, ["~> 0.6.2"])
77
- s.add_dependency(%q<rspec>, ["~> 2.11.0"])
78
- s.add_dependency(%q<yard>, [">= 0.5.5"])
77
+ s.add_dependency(%q<timecop>, ["<= 0.6.2.2"])
78
+ s.add_dependency(%q<rack-test>, [">= 0"])
79
+ s.add_dependency(%q<rspec>, [">= 0"])
80
+ s.add_dependency(%q<yard>, [">= 0"])
81
+ s.add_dependency(%q<simplecov>, [">= 0"])
79
82
  s.add_dependency(%q<redcarpet>, [">= 0"])
80
83
  s.add_dependency(%q<rake>, [">= 0"])
81
84
  s.add_dependency(%q<jeweler>, [">= 0"])
82
85
  end
83
86
  else
84
87
  s.add_dependency(%q<rack>, [">= 1.0.0"])
85
- s.add_dependency(%q<timecop>, ["~> 0.5.2"])
86
- s.add_dependency(%q<rack-test>, ["~> 0.6.2"])
87
- s.add_dependency(%q<rspec>, ["~> 2.11.0"])
88
- s.add_dependency(%q<yard>, [">= 0.5.5"])
88
+ s.add_dependency(%q<timecop>, ["<= 0.6.2.2"])
89
+ s.add_dependency(%q<rack-test>, [">= 0"])
90
+ s.add_dependency(%q<rspec>, [">= 0"])
91
+ s.add_dependency(%q<yard>, [">= 0"])
92
+ s.add_dependency(%q<simplecov>, [">= 0"])
89
93
  s.add_dependency(%q<redcarpet>, [">= 0"])
90
94
  s.add_dependency(%q<rake>, [">= 0"])
91
95
  s.add_dependency(%q<jeweler>, [">= 0"])
@@ -23,7 +23,6 @@ module Rack; module Throttle
23
23
  def initialize(app, options = {})
24
24
  rules = options.delete(:rules) || {}
25
25
  @app, @options, @matchers = app, options, []
26
- @matchers += Array(rules[:ip]).map { |rule| IpMatcher.new(rule) } if rules[:ip]
27
26
  @matchers += Array(rules[:url]).map { |rule| UrlMatcher.new(rule) } if rules[:url]
28
27
  @matchers += Array(rules[:user_agent]).map { |rule| UserAgentMatcher.new(rule) } if rules[:user_agent]
29
28
  @matchers += Array(rules[:method]).map { |rule| MethodMatcher.new(rule) } if rules[:method]
@@ -197,7 +196,8 @@ module Rack; module Throttle
197
196
  #
198
197
  # @return [Array(Integer, Hash, #each)]
199
198
  def rate_limit_exceeded
200
- headers = respond_to?(:retry_after) ? {'Retry-After' => retry_after.to_f.ceil.to_s} : {}
199
+ return_retry_after = options[:return_retry_after] || false
200
+ headers = (respond_to?(:retry_after) && return_retry_after) ? {'Retry-After' => retry_after.to_f.ceil.to_s} : {}
201
201
  http_error(options[:code] || 403, options[:message] || 'Rate Limit Exceeded', headers)
202
202
  end
203
203
 
@@ -2,8 +2,8 @@ module Rack; module Throttle
2
2
  ##
3
3
  # This rate limiter strategy throttles the application with
4
4
  # a sliding window (implemented as a leaky bucket). It operates
5
- # on second-level resolution. It takes :burst and :average
6
- # options, which correspond to the maximum size of a traffic
5
+ # on second-level resolution. It takes :burst and :average
6
+ # options, which correspond to the maximum size of a traffic
7
7
  # burst, and the maximum allowed average traffic level.
8
8
  class SlidingWindow < Limiter
9
9
  ##
@@ -18,7 +18,7 @@ module Rack; module Throttle
18
18
  end
19
19
 
20
20
  ##
21
- # Returns `true` if the request conforms to the
21
+ # Returns `true` if the request conforms to the
22
22
  # specified :average and :burst rules
23
23
  #
24
24
  # @param [Rack::Request] request
@@ -29,7 +29,7 @@ module Rack; module Throttle
29
29
  bucket = cache_get(key) rescue nil
30
30
  bucket ||= LeakyBucket.new(options[:burst], options[:average])
31
31
  bucket.maximum, bucket.outflow = options[:burst], options[:average]
32
- bucket.leak!
32
+ bucket.leak!
33
33
  bucket.increment!
34
34
  allowed = !bucket.full?
35
35
  begin
@@ -44,6 +44,15 @@ module Rack; module Throttle
44
44
  end
45
45
  end
46
46
 
47
+ ##
48
+ # Returns the number of seconds before the client is allowed to retry an
49
+ # HTTP request.
50
+ #
51
+ # @return [Float]
52
+ def retry_after
53
+ @retry_after ||= (1.0 / options[:average].to_f)
54
+ end
55
+
47
56
  ###
48
57
  # LeakyBucket is an internal class used to implement the
49
58
  # SlidingWindow limiter strategy. It is a (slightly tweaked)
@@ -67,7 +76,7 @@ module Rack; module Throttle
67
76
  loss = (outflow * time).to_f
68
77
  if loss > 0
69
78
  @count -= loss
70
- @last_touched = t
79
+ @last_touched = t
71
80
  end
72
81
  end
73
82
 
@@ -4,7 +4,7 @@ module Rack; module Throttle
4
4
  # requested. For instance, you may care about limiting requests
5
5
  # to a machine-consumed API, but not be concerned about requests
6
6
  # coming from browsers.
7
- # UrlMatchers take Regexp object to matcha gainst the request path.
7
+ # UrlMatchers take Regexp object to match against the request path.
8
8
  class UrlMatcher < Matcher
9
9
  ###
10
10
  # @param [Rack::Request] request
@@ -1,8 +1,8 @@
1
1
  module Rack; module Throttle
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 7
5
- TINY = 1
4
+ MINOR = 8
5
+ TINY = 0
6
6
  EXTRA = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
@@ -10,18 +10,18 @@ describe Rack::Throttle::Daily do
10
10
 
11
11
  it "should be allowed if not seen this day" do
12
12
  get "/foo"
13
- last_response.body.should show_allowed_response
13
+ expect(last_response.body).to show_allowed_response
14
14
  end
15
-
15
+
16
16
  it "should be allowed if seen fewer than the max allowed per day" do
17
17
  2.times { get "/foo" }
18
- last_response.body.should show_allowed_response
18
+ expect(last_response.body).to show_allowed_response
19
19
  end
20
-
20
+
21
21
  it "should not be allowed if seen more times than the max allowed per day" do
22
22
  4.times { get "/foo" }
23
- last_response.body.should show_throttled_response
23
+ expect(last_response.body).to show_throttled_response
24
24
  end
25
-
25
+
26
26
  # TODO mess with time travelling and requests to make sure no overlap
27
27
  end
@@ -10,18 +10,18 @@ describe Rack::Throttle::Hourly do
10
10
 
11
11
  it "should be allowed if not seen this hour" do
12
12
  get "/foo"
13
- last_response.body.should show_allowed_response
13
+ expect(last_response.body).to show_allowed_response
14
14
  end
15
-
15
+
16
16
  it "should be allowed if seen fewer than the max allowed per hour" do
17
17
  2.times { get "/foo" }
18
- last_response.body.should show_allowed_response
18
+ expect(last_response.body).to show_allowed_response
19
19
  end
20
-
20
+
21
21
  it "should not be allowed if seen more times than the max allowed per hour" do
22
22
  4.times { get "/foo" }
23
- last_response.body.should show_throttled_response
23
+ expect(last_response.body).to show_throttled_response
24
24
  end
25
-
25
+
26
26
  # TODO mess with time travelling and requests to make sure no overlap
27
27
  end
@@ -3,7 +3,7 @@ require File.join(File.dirname(__FILE__), '..', 'spec_helper')
3
3
 
4
4
  describe Rack::Throttle::Interval do
5
5
  include Rack::Test::Methods
6
-
6
+
7
7
  def app
8
8
  @target_app ||= example_target_app
9
9
  @app ||= Rack::Throttle::Interval.new(@target_app, :min => 0.1)
@@ -11,9 +11,9 @@ describe Rack::Throttle::Interval do
11
11
 
12
12
  it "should allow the request if the source has not been seen" do
13
13
  get "/foo"
14
- last_response.body.should show_allowed_response
14
+ expect(last_response.body).to show_allowed_response
15
15
  end
16
-
16
+
17
17
  it "should allow the request if the source has not been seen in the current interval" do
18
18
  Timecop.freeze do
19
19
  get "/foo"
@@ -21,25 +21,25 @@ describe Rack::Throttle::Interval do
21
21
  get "/foo"
22
22
  end
23
23
  end
24
- last_response.body.should show_allowed_response
24
+ expect(last_response.body).to show_allowed_response
25
25
  end
26
-
26
+
27
27
  it "should not allow the request if the source has been seen inside the current interval" do
28
28
  Timecop.freeze do
29
29
  2.times { get "/foo" }
30
30
  end
31
- last_response.body.should show_throttled_response
31
+ expect(last_response.body).to show_throttled_response
32
32
  end
33
-
33
+
34
34
  it "should gracefully allow the request if the cache bombs on getting" do
35
- app.should_receive(:cache_get).and_raise(StandardError)
35
+ expect(app).to receive(:cache_get).and_raise(StandardError)
36
36
  get "/foo"
37
- last_response.body.should show_allowed_response
37
+ expect(last_response.body).to show_allowed_response
38
38
  end
39
-
39
+
40
40
  it "should gracefully allow the request if the cache bombs on setting" do
41
- app.should_receive(:cache_set).and_raise(StandardError)
41
+ expect(app).to receive(:cache_set).and_raise(StandardError)
42
42
  get "/foo"
43
- last_response.body.should show_allowed_response
43
+ expect(last_response.body).to show_allowed_response
44
44
  end
45
45
  end
@@ -7,44 +7,44 @@ describe Rack::Throttle::Limiter do
7
7
  @target_app ||= example_target_app
8
8
  @app ||= Rack::Throttle::Limiter.new(@target_app)
9
9
  end
10
-
10
+
11
11
  describe "basic calling" do
12
12
  it "should return the example app" do
13
13
  get "/foo"
14
- last_response.body.should show_allowed_response
14
+ expect(last_response.body).to show_allowed_response
15
15
  end
16
-
16
+
17
17
  it "should call the application if allowed" do
18
- app.should_receive(:allowed?).and_return(true)
18
+ expect(app).to receive(:allowed?).and_return(true)
19
19
  get "/foo"
20
- last_response.body.should show_allowed_response
20
+ expect(last_response.body).to show_allowed_response
21
21
  end
22
-
22
+
23
23
  it "should give a rate limit exceeded message if not allowed" do
24
- app.should_receive(:allowed?).and_return(false)
24
+ expect(app).to receive(:allowed?).and_return(false)
25
25
  get "/foo"
26
- last_response.body.should show_throttled_response
26
+ expect(last_response.body).to show_throttled_response
27
27
  end
28
28
  end
29
-
29
+
30
30
  describe "allowed?" do
31
31
  it "should return true if whitelisted" do
32
- app.should_receive(:whitelisted?).and_return(true)
32
+ expect(app).to receive(:whitelisted?).and_return(true)
33
33
  get "/foo"
34
- last_response.body.should show_allowed_response
34
+ expect(last_response.body).to show_allowed_response
35
35
  end
36
-
36
+
37
37
  it "should return false if blacklisted" do
38
- app.should_receive(:blacklisted?).and_return(true)
38
+ expect(app).to receive(:blacklisted?).and_return(true)
39
39
  get "/foo"
40
- last_response.body.should show_throttled_response
40
+ expect(last_response.body).to show_throttled_response
41
41
  end
42
-
42
+
43
43
  it "should return true if not whitelisted or blacklisted" do
44
- app.should_receive(:whitelisted?).and_return(false)
45
- app.should_receive(:blacklisted?).and_return(false)
44
+ expect(app).to receive(:whitelisted?).and_return(false)
45
+ expect(app).to receive(:blacklisted?).and_return(false)
46
46
  get "/foo"
47
- last_response.body.should show_allowed_response
47
+ expect(last_response.body).to show_allowed_response
48
48
  end
49
49
  end
50
50
 
@@ -19,28 +19,28 @@ describe Rack::Throttle::SlidingWindow do
19
19
 
20
20
  it "should allow the request if the source has not been seen at all" do
21
21
  get "/foo"
22
- last_response.body.should show_allowed_response
22
+ expect(last_response.body).to show_allowed_response
23
23
  end
24
-
24
+
25
25
  it "should allow the request if the rate is above-average but within the burst rule" do
26
26
  Timecop.freeze(@time) { get "/foo" }
27
27
  Timecop.freeze(@time + 0.5) { get "/foo" }
28
- last_response.body.should show_allowed_response
28
+ expect(last_response.body).to show_allowed_response
29
29
  end
30
30
 
31
31
  it "should not allow the request if the rate is greater than the burst rule" do
32
32
  Timecop.freeze(@time) { get "/foo" }
33
33
  Timecop.freeze(@time + 0.3) { get "/foo" }
34
34
  Timecop.freeze(@time + 0.6) { get "/foo" }
35
- last_response.body.should show_throttled_response
35
+ expect(last_response.body).to show_throttled_response
36
36
  end
37
-
37
+
38
38
  it "should allow the request if the rate is less than the average" do
39
39
  Timecop.freeze(@time) { get "/foo" }
40
40
  Timecop.freeze(@time + 0.5) { get "/foo" }
41
41
  Timecop.freeze(@time + 2) { get "/foo" }
42
42
 
43
- last_response.body.should show_allowed_response
43
+ expect(last_response.body).to show_allowed_response
44
44
  end
45
45
 
46
46
  it "should not allow the request if the rate is more than the average" do
@@ -49,19 +49,19 @@ describe Rack::Throttle::SlidingWindow do
49
49
  Timecop.freeze(@time + 1) { get "/foo" }
50
50
  Timecop.freeze(@time + 1.5) { get "/foo" }
51
51
 
52
- last_response.body.should show_throttled_response
52
+ expect(last_response.body).to show_throttled_response
53
53
  end
54
54
 
55
55
  it "should gracefully allow the request if the cache bombs on getting" do
56
- app.should_receive(:cache_get).and_raise(StandardError)
56
+ expect(app).to receive(:cache_get).and_raise(StandardError)
57
57
  get "/foo"
58
- last_response.body.should show_allowed_response
58
+ expect(last_response.body).to show_allowed_response
59
59
  end
60
-
60
+
61
61
  it "should gracefully allow the request if the cache bombs on setting" do
62
- app.should_receive(:cache_set).and_raise(StandardError)
62
+ expect(app).to receive(:cache_set).and_raise(StandardError)
63
63
  get "/foo"
64
- last_response.body.should show_allowed_response
64
+ expect(last_response.body).to show_allowed_response
65
65
  end
66
66
  end
67
67
 
@@ -9,19 +9,19 @@ describe Rack::Throttle::MethodMatcher do
9
9
  end
10
10
 
11
11
  it "should not bother checking if the path doesn't match the rule" do
12
- app.should_not_receive(:allowed?)
12
+ expect(app).not_to receive(:allowed?)
13
13
  get "/foo"
14
- last_response.body.should show_allowed_response
14
+ expect(last_response.body).to show_allowed_response
15
15
  end
16
-
16
+
17
17
  it "should check if the path matches the rule" do
18
- app.should_receive(:allowed?).and_return(false)
18
+ expect(app).to receive(:allowed?).and_return(false)
19
19
  post "/foo"
20
- last_response.body.should show_throttled_response
20
+ expect(last_response.body).to show_throttled_response
21
21
  end
22
22
 
23
23
  it "should append the rule to the cache key" do
24
24
  post "/foo"
25
- app.send(:cache_key, last_request).should == "127.0.0.1:meth-post"
25
+ expect(app.send(:cache_key, last_request)).to eq "127.0.0.1:meth-post"
26
26
  end
27
27
  end
@@ -9,20 +9,20 @@ describe Rack::Throttle::UrlMatcher do
9
9
  end
10
10
 
11
11
  it "should not bother checking if the path doesn't match the rule" do
12
- app.should_not_receive(:allowed?)
12
+ expect(app).not_to receive(:allowed?)
13
13
  get "/bar"
14
- last_response.body.should show_allowed_response
14
+ expect(last_response.body).to show_allowed_response
15
15
  end
16
-
16
+
17
17
  it "should check if the path matches the rule" do
18
- app.should_receive(:allowed?).and_return(false)
18
+ expect(app).to receive(:allowed?).and_return(false)
19
19
  get "/foo"
20
- last_response.body.should show_throttled_response
20
+ expect(last_response.body).to show_throttled_response
21
21
  end
22
22
 
23
23
  it "should append the rule to the cache key" do
24
24
  get "/foo"
25
- app.send(:cache_key, last_request).should == "127.0.0.1:url-/foo/"
25
+ expect(app.send(:cache_key, last_request)).to eq "127.0.0.1:url-/foo/"
26
26
  end
27
27
  end
28
28
 
@@ -9,20 +9,20 @@ describe Rack::Throttle::UserAgentMatcher do
9
9
  end
10
10
 
11
11
  it "should not bother checking if the path doesn't match the rule" do
12
- app.should_not_receive(:allowed?)
12
+ expect(app).not_to receive(:allowed?)
13
13
  get "/foo"
14
- last_response.body.should show_allowed_response
14
+ expect(last_response.body).to show_allowed_response
15
15
  end
16
16
 
17
17
  it "should check if the path matches the rule" do
18
- app.should_receive(:allowed?).and_return(false)
18
+ expect(app).to receive(:allowed?).and_return(false)
19
19
  header 'User-Agent', 'blahdeblah GoogleBot owns your soul'
20
20
  get "/foo"
21
- last_response.body.should show_throttled_response
21
+ expect(last_response.body).to show_throttled_response
22
22
  end
23
23
 
24
24
  it "should append the rule to the cache key" do
25
25
  get "/foo"
26
- app.send(:cache_key, last_request).should == "127.0.0.1:ua-/google/i"
26
+ expect(app.send(:cache_key, last_request)).to eq "127.0.0.1:ua-/google/i"
27
27
  end
28
28
  end
@@ -3,9 +3,14 @@ require "rack/test"
3
3
  require "rack/throttle"
4
4
  require "timecop"
5
5
 
6
+ unless RUBY_VERSION.match(/1\.8/)
7
+ require 'simplecov'
8
+ SimpleCov.start
9
+ end
10
+
6
11
  def example_target_app
7
12
  @target_app = double("Example Rack App")
8
- @target_app.stub(:call).with(any_args()).and_return([200, {}, "Example App Body"])
13
+ allow(@target_app).to receive(:call).with(any_args()).and_return([200, {}, "Example App Body"])
9
14
  @target_app
10
15
  end
11
16
 
@@ -13,34 +18,34 @@ RSpec::Matchers.define :show_allowed_response do
13
18
  match do |body|
14
19
  body.include?("Example App Body")
15
20
  end
16
-
17
- failure_message_for_should do
18
- "expected response to show the allowed response"
19
- end
20
21
 
21
- failure_message_for_should_not do
22
- "expected response not to show the allowed response"
22
+ failure_message do
23
+ "expected response to show the allowed response"
23
24
  end
24
-
25
+
26
+ failure_message_when_negated do
27
+ "expected response not to show the allowed response"
28
+ end
29
+
25
30
  description do
26
31
  "expected the allowed response"
27
- end
32
+ end
28
33
  end
29
34
 
30
35
  RSpec::Matchers.define :show_throttled_response do
31
36
  match do |body|
32
37
  body.include?("Rate Limit Exceeded")
33
38
  end
34
-
35
- failure_message_for_should do
36
- "expected response to show the throttled response"
37
- end
38
39
 
39
- failure_message_for_should_not do
40
- "expected response not to show the throttled response"
40
+ failure_message do
41
+ "expected response to show the throttled response"
42
+ end
43
+
44
+ failure_message do
45
+ "expected response not to show the throttled response"
41
46
  end
42
-
47
+
43
48
  description do
44
49
  "expected the throttled response"
45
- end
50
+ end
46
51
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: improved-rack-throttle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
5
- prerelease:
4
+ version: 0.8.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Ben Somers
@@ -11,134 +10,132 @@ authors:
11
10
  autorequire:
12
11
  bindir: bin
13
12
  cert_chain: []
14
- date: 2013-05-09 00:00:00.000000000 Z
13
+ date: 2014-09-22 00:00:00.000000000 Z
15
14
  dependencies:
16
15
  - !ruby/object:Gem::Dependency
17
16
  name: rack
18
17
  requirement: !ruby/object:Gem::Requirement
19
- none: false
20
18
  requirements:
21
- - - ! '>='
19
+ - - '>='
22
20
  - !ruby/object:Gem::Version
23
21
  version: 1.0.0
24
22
  type: :runtime
25
23
  prerelease: false
26
24
  version_requirements: !ruby/object:Gem::Requirement
27
- none: false
28
25
  requirements:
29
- - - ! '>='
26
+ - - '>='
30
27
  - !ruby/object:Gem::Version
31
28
  version: 1.0.0
32
29
  - !ruby/object:Gem::Dependency
33
30
  name: timecop
34
31
  requirement: !ruby/object:Gem::Requirement
35
- none: false
36
32
  requirements:
37
- - - ~>
33
+ - - <=
38
34
  - !ruby/object:Gem::Version
39
- version: 0.5.2
35
+ version: 0.6.2.2
40
36
  type: :development
41
37
  prerelease: false
42
38
  version_requirements: !ruby/object:Gem::Requirement
43
- none: false
44
39
  requirements:
45
- - - ~>
40
+ - - <=
46
41
  - !ruby/object:Gem::Version
47
- version: 0.5.2
42
+ version: 0.6.2.2
48
43
  - !ruby/object:Gem::Dependency
49
44
  name: rack-test
50
45
  requirement: !ruby/object:Gem::Requirement
51
- none: false
52
46
  requirements:
53
- - - ~>
47
+ - - '>='
54
48
  - !ruby/object:Gem::Version
55
- version: 0.6.2
49
+ version: '0'
56
50
  type: :development
57
51
  prerelease: false
58
52
  version_requirements: !ruby/object:Gem::Requirement
59
- none: false
60
53
  requirements:
61
- - - ~>
54
+ - - '>='
62
55
  - !ruby/object:Gem::Version
63
- version: 0.6.2
56
+ version: '0'
64
57
  - !ruby/object:Gem::Dependency
65
58
  name: rspec
66
59
  requirement: !ruby/object:Gem::Requirement
67
- none: false
68
60
  requirements:
69
- - - ~>
61
+ - - '>='
70
62
  - !ruby/object:Gem::Version
71
- version: 2.11.0
63
+ version: '0'
72
64
  type: :development
73
65
  prerelease: false
74
66
  version_requirements: !ruby/object:Gem::Requirement
75
- none: false
76
67
  requirements:
77
- - - ~>
68
+ - - '>='
78
69
  - !ruby/object:Gem::Version
79
- version: 2.11.0
70
+ version: '0'
80
71
  - !ruby/object:Gem::Dependency
81
72
  name: yard
82
73
  requirement: !ruby/object:Gem::Requirement
83
- none: false
84
74
  requirements:
85
- - - ! '>='
75
+ - - '>='
86
76
  - !ruby/object:Gem::Version
87
- version: 0.5.5
77
+ version: '0'
88
78
  type: :development
89
79
  prerelease: false
90
80
  version_requirements: !ruby/object:Gem::Requirement
91
- none: false
92
81
  requirements:
93
- - - ! '>='
82
+ - - '>='
94
83
  - !ruby/object:Gem::Version
95
- version: 0.5.5
84
+ version: '0'
85
+ - !ruby/object:Gem::Dependency
86
+ name: simplecov
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
96
99
  - !ruby/object:Gem::Dependency
97
100
  name: redcarpet
98
101
  requirement: !ruby/object:Gem::Requirement
99
- none: false
100
102
  requirements:
101
- - - ! '>='
103
+ - - '>='
102
104
  - !ruby/object:Gem::Version
103
105
  version: '0'
104
106
  type: :development
105
107
  prerelease: false
106
108
  version_requirements: !ruby/object:Gem::Requirement
107
- none: false
108
109
  requirements:
109
- - - ! '>='
110
+ - - '>='
110
111
  - !ruby/object:Gem::Version
111
112
  version: '0'
112
113
  - !ruby/object:Gem::Dependency
113
114
  name: rake
114
115
  requirement: !ruby/object:Gem::Requirement
115
- none: false
116
116
  requirements:
117
- - - ! '>='
117
+ - - '>='
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0'
120
120
  type: :development
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
123
- none: false
124
123
  requirements:
125
- - - ! '>='
124
+ - - '>='
126
125
  - !ruby/object:Gem::Version
127
126
  version: '0'
128
127
  - !ruby/object:Gem::Dependency
129
128
  name: jeweler
130
129
  requirement: !ruby/object:Gem::Requirement
131
- none: false
132
130
  requirements:
133
- - - ! '>='
131
+ - - '>='
134
132
  - !ruby/object:Gem::Version
135
133
  version: '0'
136
134
  type: :development
137
135
  prerelease: false
138
136
  version_requirements: !ruby/object:Gem::Requirement
139
- none: false
140
137
  requirements:
141
- - - ! '>='
138
+ - - '>='
142
139
  - !ruby/object:Gem::Version
143
140
  version: '0'
144
141
  description: Rack middleware for rate-limiting incoming HTTP requests.
@@ -149,6 +146,7 @@ extra_rdoc_files:
149
146
  - README.md
150
147
  files:
151
148
  - .document
149
+ - .travis.yml
152
150
  - Gemfile
153
151
  - Gemfile.lock
154
152
  - README.md
@@ -186,29 +184,26 @@ files:
186
184
  homepage: http://github.com/bensomers/improved-rack-throttle
187
185
  licenses:
188
186
  - Public Domain
187
+ metadata: {}
189
188
  post_install_message:
190
189
  rdoc_options: []
191
190
  require_paths:
192
191
  - lib
193
192
  required_ruby_version: !ruby/object:Gem::Requirement
194
- none: false
195
193
  requirements:
196
- - - ! '>='
194
+ - - '>='
197
195
  - !ruby/object:Gem::Version
198
196
  version: '0'
199
- segments:
200
- - 0
201
- hash: -4496223408765979053
202
197
  required_rubygems_version: !ruby/object:Gem::Requirement
203
- none: false
204
198
  requirements:
205
- - - ! '>='
199
+ - - '>='
206
200
  - !ruby/object:Gem::Version
207
201
  version: '0'
208
202
  requirements: []
209
203
  rubyforge_project:
210
- rubygems_version: 1.8.25
204
+ rubygems_version: 2.0.3
211
205
  signing_key:
212
- specification_version: 3
206
+ specification_version: 4
213
207
  summary: HTTP request rate limiter for Rack applications.
214
208
  test_files: []
209
+ has_rdoc: