improved-rack-throttle 0.6.0 → 0.7.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/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/improved-rack-throttle.gemspec +21 -19
- data/lib/rack/throttle/{daily.rb → limiters/daily.rb} +0 -0
- data/lib/rack/throttle/{hourly.rb → limiters/hourly.rb} +0 -0
- data/lib/rack/throttle/{interval.rb → limiters/interval.rb} +0 -0
- data/lib/rack/throttle/{limiter.rb → limiters/limiter.rb} +0 -1
- data/lib/rack/throttle/limiters/sliding_window.rb +79 -0
- data/lib/rack/throttle/{time_window.rb → limiters/time_window.rb} +0 -0
- data/lib/rack/throttle/{matcher.rb → matchers/matcher.rb} +0 -0
- data/lib/rack/throttle/version.rb +1 -1
- data/lib/rack/throttle.rb +10 -9
- data/spec/{daily_spec.rb → limiters/daily_spec.rb} +1 -1
- data/spec/{hourly_spec.rb → limiters/hourly_spec.rb} +1 -1
- data/spec/{interval_spec.rb → limiters/interval_spec.rb} +1 -1
- data/spec/{limiter_spec.rb → limiters/limiter_spec.rb} +1 -1
- data/spec/limiters/sliding_window_spec.rb +67 -0
- data/spec/{method_matcher_spec.rb → matchers/method_matcher_spec.rb} +1 -3
- data/spec/{url_matcher_spec.rb → matchers/url_matcher_spec.rb} +1 -1
- data/spec/{user_agent_matcher_spec.rb → matchers/user_agent_matcher_spec.rb} +2 -2
- metadata +33 -31
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -9,7 +9,7 @@ GEM
|
|
9
9
|
rake
|
10
10
|
rdoc
|
11
11
|
json (1.7.5)
|
12
|
-
rack (1.
|
12
|
+
rack (1.4.1)
|
13
13
|
rack-test (0.6.2)
|
14
14
|
rack (>= 1.0)
|
15
15
|
rake (0.9.2.2)
|
@@ -31,7 +31,7 @@ PLATFORMS
|
|
31
31
|
|
32
32
|
DEPENDENCIES
|
33
33
|
jeweler
|
34
|
-
rack (
|
34
|
+
rack (>= 1.0.0)
|
35
35
|
rack-test (~> 0.6.2)
|
36
36
|
rake
|
37
37
|
rspec (~> 2.11.0)
|
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "improved-rack-throttle"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.7.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 = "2012-10-
|
12
|
+
s.date = "2012-10-05"
|
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 = [
|
@@ -31,24 +31,26 @@ Gem::Specification.new do |s|
|
|
31
31
|
"etc/redis.ru",
|
32
32
|
"improved-rack-throttle.gemspec",
|
33
33
|
"lib/rack/throttle.rb",
|
34
|
-
"lib/rack/throttle/daily.rb",
|
35
|
-
"lib/rack/throttle/hourly.rb",
|
36
|
-
"lib/rack/throttle/interval.rb",
|
37
|
-
"lib/rack/throttle/limiter.rb",
|
38
|
-
"lib/rack/throttle/
|
34
|
+
"lib/rack/throttle/limiters/daily.rb",
|
35
|
+
"lib/rack/throttle/limiters/hourly.rb",
|
36
|
+
"lib/rack/throttle/limiters/interval.rb",
|
37
|
+
"lib/rack/throttle/limiters/limiter.rb",
|
38
|
+
"lib/rack/throttle/limiters/sliding_window.rb",
|
39
|
+
"lib/rack/throttle/limiters/time_window.rb",
|
40
|
+
"lib/rack/throttle/matchers/matcher.rb",
|
39
41
|
"lib/rack/throttle/matchers/method_matcher.rb",
|
40
42
|
"lib/rack/throttle/matchers/url_matcher.rb",
|
41
43
|
"lib/rack/throttle/matchers/user_agent_matcher.rb",
|
42
|
-
"lib/rack/throttle/time_window.rb",
|
43
44
|
"lib/rack/throttle/version.rb",
|
44
|
-
"spec/daily_spec.rb",
|
45
|
-
"spec/hourly_spec.rb",
|
46
|
-
"spec/interval_spec.rb",
|
47
|
-
"spec/limiter_spec.rb",
|
48
|
-
"spec/
|
49
|
-
"spec/
|
50
|
-
"spec/url_matcher_spec.rb",
|
51
|
-
"spec/user_agent_matcher_spec.rb"
|
45
|
+
"spec/limiters/daily_spec.rb",
|
46
|
+
"spec/limiters/hourly_spec.rb",
|
47
|
+
"spec/limiters/interval_spec.rb",
|
48
|
+
"spec/limiters/limiter_spec.rb",
|
49
|
+
"spec/limiters/sliding_window_spec.rb",
|
50
|
+
"spec/matchers/method_matcher_spec.rb",
|
51
|
+
"spec/matchers/url_matcher_spec.rb",
|
52
|
+
"spec/matchers/user_agent_matcher_spec.rb",
|
53
|
+
"spec/spec_helper.rb"
|
52
54
|
]
|
53
55
|
s.homepage = "http://github.com/bensomers/improved-rack-throttle"
|
54
56
|
s.licenses = ["Public Domain"]
|
@@ -60,7 +62,7 @@ Gem::Specification.new do |s|
|
|
60
62
|
s.specification_version = 3
|
61
63
|
|
62
64
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
63
|
-
s.add_runtime_dependency(%q<rack>, ["
|
65
|
+
s.add_runtime_dependency(%q<rack>, [">= 1.0.0"])
|
64
66
|
s.add_development_dependency(%q<timecop>, ["~> 0.5.2"])
|
65
67
|
s.add_development_dependency(%q<rack-test>, ["~> 0.6.2"])
|
66
68
|
s.add_development_dependency(%q<rspec>, ["~> 2.11.0"])
|
@@ -68,7 +70,7 @@ Gem::Specification.new do |s|
|
|
68
70
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
69
71
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
70
72
|
else
|
71
|
-
s.add_dependency(%q<rack>, ["
|
73
|
+
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
72
74
|
s.add_dependency(%q<timecop>, ["~> 0.5.2"])
|
73
75
|
s.add_dependency(%q<rack-test>, ["~> 0.6.2"])
|
74
76
|
s.add_dependency(%q<rspec>, ["~> 2.11.0"])
|
@@ -77,7 +79,7 @@ Gem::Specification.new do |s|
|
|
77
79
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
78
80
|
end
|
79
81
|
else
|
80
|
-
s.add_dependency(%q<rack>, ["
|
82
|
+
s.add_dependency(%q<rack>, [">= 1.0.0"])
|
81
83
|
s.add_dependency(%q<timecop>, ["~> 0.5.2"])
|
82
84
|
s.add_dependency(%q<rack-test>, ["~> 0.6.2"])
|
83
85
|
s.add_dependency(%q<rspec>, ["~> 2.11.0"])
|
File without changes
|
File without changes
|
File without changes
|
@@ -20,7 +20,6 @@ module Rack; module Throttle
|
|
20
20
|
# @option options [String] :key_prefix (nil)
|
21
21
|
# @option options [Integer] :code (403)
|
22
22
|
# @option options [String] :message ("Rate Limit Exceeded")
|
23
|
-
# @option options [Regexp] :url_rule (nil)
|
24
23
|
def initialize(app, options = {})
|
25
24
|
rules = options.delete(:rules) || {}
|
26
25
|
@app, @options, @matchers = app, options, []
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Rack; module Throttle
|
2
|
+
##
|
3
|
+
# This rate limiter strategy throttles the application with
|
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
|
7
|
+
# burst, and the maximum allowed average traffic level.
|
8
|
+
class SlidingWindow < Limiter
|
9
|
+
##
|
10
|
+
# @param [#call] app
|
11
|
+
# @param [Hash{Symbol => Object}] options
|
12
|
+
# @option options [Integer] :burst 5
|
13
|
+
# @option options [Float] :average 1
|
14
|
+
def initialize(app, options = {})
|
15
|
+
super
|
16
|
+
options[:burst] ||= 5
|
17
|
+
options[:average] ||= 1
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Returns `true` if sufficient time (equal to or more than
|
22
|
+
# {#minimum_interval}) has passed since the last request and the given
|
23
|
+
# present `request`.
|
24
|
+
#
|
25
|
+
# @param [Rack::Request] request
|
26
|
+
# @return [Boolean]
|
27
|
+
def allowed?(request)
|
28
|
+
t1 = request_start_time(request)
|
29
|
+
key = cache_key(request)
|
30
|
+
bucket = cache_get(key) rescue nil
|
31
|
+
bucket ||= LeakyBucket.new(options[:burst], options[:average])
|
32
|
+
bucket.maximum, bucket.outflow = options[:burst], options[:average]
|
33
|
+
bucket.leak!
|
34
|
+
bucket.increment!
|
35
|
+
allowed = !bucket.full?
|
36
|
+
begin
|
37
|
+
cache_set(key, bucket)
|
38
|
+
allowed
|
39
|
+
rescue StandardError => e
|
40
|
+
allowed = true
|
41
|
+
# If an error occurred while trying to update the timestamp stored
|
42
|
+
# in the cache, we will fall back to allowing the request through.
|
43
|
+
# This prevents the Rack application blowing up merely due to a
|
44
|
+
# backend cache server (Memcached, Redis, etc.) being offline.
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class LeakyBucket
|
49
|
+
attr_accessor :maximum, :outflow
|
50
|
+
attr_reader :count, :last_touched
|
51
|
+
|
52
|
+
def initialize(maximum, outflow)
|
53
|
+
@maximum, @outflow = maximum, outflow
|
54
|
+
@count, @last_touched = 0, Time.now
|
55
|
+
end
|
56
|
+
|
57
|
+
def leak!
|
58
|
+
t = Time.now
|
59
|
+
time = t - last_touched
|
60
|
+
loss = (outflow * time).to_f
|
61
|
+
if loss > 0
|
62
|
+
@count -= loss
|
63
|
+
@last_touched = t
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def increment!
|
68
|
+
@count = 0 if count < 0
|
69
|
+
@count += 1
|
70
|
+
@count = maximum if count > maximum
|
71
|
+
end
|
72
|
+
|
73
|
+
def full?
|
74
|
+
count == maximum
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end; end
|
File without changes
|
File without changes
|
data/lib/rack/throttle.rb
CHANGED
@@ -2,15 +2,16 @@ require 'rack'
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
module Throttle
|
5
|
-
autoload :Limiter,
|
6
|
-
autoload :Interval,
|
7
|
-
autoload :TimeWindow,
|
8
|
-
autoload :Daily,
|
9
|
-
autoload :Hourly,
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
13
|
-
autoload :
|
5
|
+
autoload :Limiter, 'rack/throttle/limiters/limiter'
|
6
|
+
autoload :Interval, 'rack/throttle/limiters/interval'
|
7
|
+
autoload :TimeWindow, 'rack/throttle/limiters/time_window'
|
8
|
+
autoload :Daily, 'rack/throttle/limiters/daily'
|
9
|
+
autoload :Hourly, 'rack/throttle/limiters/hourly'
|
10
|
+
autoload :SlidingWindow, 'rack/throttle/limiters/sliding_window'
|
11
|
+
autoload :VERSION, 'rack/throttle/version'
|
12
|
+
autoload :Matcher, 'rack/throttle/matchers/matcher'
|
13
|
+
autoload :UrlMatcher, 'rack/throttle/matchers/url_matcher'
|
14
|
+
autoload :MethodMatcher, 'rack/throttle/matchers/method_matcher'
|
14
15
|
autoload :UserAgentMatcher, 'rack/throttle/matchers/user_agent_matcher'
|
15
16
|
end
|
16
17
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe Rack::Throttle::SlidingWindow do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
def app
|
7
|
+
@target_app ||= example_target_app
|
8
|
+
@app ||= Rack::Throttle::SlidingWindow.new(@target_app, :burst => 2, :average => 1)
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
@time = Time.now
|
13
|
+
Timecop.freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
Timecop.return
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should allow the request if the source has not been seen at all" do
|
21
|
+
get "/foo"
|
22
|
+
last_response.body.should show_allowed_response
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow the request if the rate is above-average but within the burst rule" do
|
26
|
+
Timecop.freeze(@time) { get "/foo" }
|
27
|
+
Timecop.freeze(@time + 0.5) { get "/foo" }
|
28
|
+
last_response.body.should show_allowed_response
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should not allow the request if the rate is greater than the burst rule" do
|
32
|
+
Timecop.freeze(@time) { get "/foo" }
|
33
|
+
Timecop.freeze(@time + 0.3) { get "/foo" }
|
34
|
+
Timecop.freeze(@time + 0.6) { get "/foo" }
|
35
|
+
last_response.body.should show_throttled_response
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should allow the request if the rate is less than the average" do
|
39
|
+
Timecop.freeze(@time) { get "/foo" }
|
40
|
+
Timecop.freeze(@time + 0.5) { get "/foo" }
|
41
|
+
Timecop.freeze(@time + 2) { get "/foo" }
|
42
|
+
|
43
|
+
last_response.body.should show_allowed_response
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not allow the request if the rate is more than the average" do
|
47
|
+
Timecop.freeze(@time) { get "/foo" }
|
48
|
+
Timecop.freeze(@time + 0.5) { get "/foo" }
|
49
|
+
Timecop.freeze(@time + 1) { get "/foo" }
|
50
|
+
Timecop.freeze(@time + 1.5) { get "/foo" }
|
51
|
+
|
52
|
+
last_response.body.should show_throttled_response
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should gracefully allow the request if the cache bombs on getting" do
|
56
|
+
app.should_receive(:cache_get).and_raise(StandardError)
|
57
|
+
get "/foo"
|
58
|
+
last_response.body.should show_allowed_response
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should gracefully allow the request if the cache bombs on setting" do
|
62
|
+
app.should_receive(:cache_set).and_raise(StandardError)
|
63
|
+
get "/foo"
|
64
|
+
last_response.body.should show_allowed_response
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__)
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
2
|
|
3
3
|
describe Rack::Throttle::MethodMatcher do
|
4
4
|
include Rack::Test::Methods
|
@@ -25,5 +25,3 @@ describe Rack::Throttle::MethodMatcher do
|
|
25
25
|
app.send(:cache_key, last_request).should == "127.0.0.1:meth-post"
|
26
26
|
end
|
27
27
|
end
|
28
|
-
|
29
|
-
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__)
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
2
|
|
3
3
|
describe Rack::Throttle::UserAgentMatcher do
|
4
4
|
include Rack::Test::Methods
|
@@ -13,7 +13,7 @@ describe Rack::Throttle::UserAgentMatcher do
|
|
13
13
|
get "/foo"
|
14
14
|
last_response.body.should show_allowed_response
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should check if the path matches the rule" do
|
18
18
|
app.should_receive(:allowed?).and_return(false)
|
19
19
|
header 'User-Agent', 'blahdeblah GoogleBot owns your soul'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: improved-rack-throttle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,22 +11,22 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-10-
|
14
|
+
date: 2012-10-05 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rack
|
18
|
-
requirement: &
|
18
|
+
requirement: &70296124961520 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
|
-
- -
|
21
|
+
- - ! '>='
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: 1.0.0
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *70296124961520
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: timecop
|
29
|
-
requirement: &
|
29
|
+
requirement: &70296124960800 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ~>
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: 0.5.2
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *70296124960800
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: rack-test
|
40
|
-
requirement: &
|
40
|
+
requirement: &70296124960000 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: 0.6.2
|
46
46
|
type: :development
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *70296124960000
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: rspec
|
51
|
-
requirement: &
|
51
|
+
requirement: &70296124959520 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ~>
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: 2.11.0
|
57
57
|
type: :development
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *70296124959520
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: yard
|
62
|
-
requirement: &
|
62
|
+
requirement: &70296124958980 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: 0.5.5
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *70296124958980
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: rake
|
73
|
-
requirement: &
|
73
|
+
requirement: &70296124958220 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: '0'
|
79
79
|
type: :development
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *70296124958220
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: jeweler
|
84
|
-
requirement: &
|
84
|
+
requirement: &70296124957640 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *70296124957640
|
93
93
|
description: Rack middleware for rate-limiting incoming HTTP requests.
|
94
94
|
email: somers.ben@gmail.com
|
95
95
|
executables: []
|
@@ -112,24 +112,26 @@ files:
|
|
112
112
|
- etc/redis.ru
|
113
113
|
- improved-rack-throttle.gemspec
|
114
114
|
- lib/rack/throttle.rb
|
115
|
-
- lib/rack/throttle/daily.rb
|
116
|
-
- lib/rack/throttle/hourly.rb
|
117
|
-
- lib/rack/throttle/interval.rb
|
118
|
-
- lib/rack/throttle/limiter.rb
|
119
|
-
- lib/rack/throttle/
|
115
|
+
- lib/rack/throttle/limiters/daily.rb
|
116
|
+
- lib/rack/throttle/limiters/hourly.rb
|
117
|
+
- lib/rack/throttle/limiters/interval.rb
|
118
|
+
- lib/rack/throttle/limiters/limiter.rb
|
119
|
+
- lib/rack/throttle/limiters/sliding_window.rb
|
120
|
+
- lib/rack/throttle/limiters/time_window.rb
|
121
|
+
- lib/rack/throttle/matchers/matcher.rb
|
120
122
|
- lib/rack/throttle/matchers/method_matcher.rb
|
121
123
|
- lib/rack/throttle/matchers/url_matcher.rb
|
122
124
|
- lib/rack/throttle/matchers/user_agent_matcher.rb
|
123
|
-
- lib/rack/throttle/time_window.rb
|
124
125
|
- lib/rack/throttle/version.rb
|
125
|
-
- spec/daily_spec.rb
|
126
|
-
- spec/hourly_spec.rb
|
127
|
-
- spec/interval_spec.rb
|
128
|
-
- spec/limiter_spec.rb
|
129
|
-
- spec/
|
126
|
+
- spec/limiters/daily_spec.rb
|
127
|
+
- spec/limiters/hourly_spec.rb
|
128
|
+
- spec/limiters/interval_spec.rb
|
129
|
+
- spec/limiters/limiter_spec.rb
|
130
|
+
- spec/limiters/sliding_window_spec.rb
|
131
|
+
- spec/matchers/method_matcher_spec.rb
|
132
|
+
- spec/matchers/url_matcher_spec.rb
|
133
|
+
- spec/matchers/user_agent_matcher_spec.rb
|
130
134
|
- spec/spec_helper.rb
|
131
|
-
- spec/url_matcher_spec.rb
|
132
|
-
- spec/user_agent_matcher_spec.rb
|
133
135
|
homepage: http://github.com/bensomers/improved-rack-throttle
|
134
136
|
licenses:
|
135
137
|
- Public Domain
|
@@ -145,7 +147,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
145
147
|
version: '0'
|
146
148
|
segments:
|
147
149
|
- 0
|
148
|
-
hash:
|
150
|
+
hash: 3964473901145440251
|
149
151
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
152
|
none: false
|
151
153
|
requirements:
|