Added throttling, max_content_length, and max_events_per_request - #150

Andrew Kane committed Mar 07, 2016
commit ec2bb23471af3e4ea7f81253915732f5c404be0e
Showing 7 changed files with 56 additions and 2 deletions
CHANGELOG.md +5 -0
@@ @@ -1,3 +1,8 @@
+ ## 1.3.0
+
+ - Added throttling
+ - Added `max_content_length` and `max_events_per_request`
+
## 1.2.2
- Fixed issue with latest version of `browser` gem
ahoy_matey.gemspec +1 -0
@@ @@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
spec.add_dependency "request_store"
spec.add_dependency "uuidtools"
spec.add_dependency "errbase"
+ spec.add_dependency "rack-attack"
spec.add_development_dependency "bundler", "~> 1.5"
spec.add_development_dependency "rake"
app/controllers/ahoy/base_controller.rb +11 -0
@@ @@ -4,12 +4,23 @@ module Ahoy
filters = _process_action_callbacks.map(&:filter) - [:load_authlogic]
if respond_to?(:skip_action)
skip_action *filters
+ before_action :verify_request_size
else
skip_filter *filters
+ before_filter :verify_request_size
end
+ protected
+
def ahoy
@ahoy ||= Ahoy::Tracker.new(controller: self, api: true)
end
+
+ def verify_request_size
+ if request.content_length > Ahoy.max_content_length
+ logger.info "[ahoy] Payload too large"
+ render text: "Payload too large\n", status: 413
+ end
+ end
end
end
app/controllers/ahoy/events_controller.rb +1 -1
@@ @@ -14,7 +14,7 @@ module Ahoy
end
end
- events.each do |event|
+ events.first(Ahoy.max_events_per_request).each do |event|
time = Time.zone.parse(event["time"]) rescue nil
# timestamp is deprecated
ahoy.rb b/lib/ahoy.rb +15 -0
@@ @@ -62,6 +62,21 @@ module Ahoy
mattr_accessor :geocode
self.geocode = true
+ mattr_accessor :max_content_length
+ self.max_content_length = 8192
+
+ mattr_accessor :max_events_per_request
+ self.max_events_per_request = 10
+
+ mattr_accessor :throttle
+ self.throttle = true
+
+ mattr_accessor :throttle_limit
+ self.throttle_limit = 20
+
+ mattr_accessor :throttle_period
+ self.throttle_period = 1.minute
+
def self.ensure_uuid(id)
valid = UUIDTools::UUID.parse(id) rescue nil
if valid
ahoy/engine.rb b/lib/ahoy/engine.rb +6 -1
@@ @@ -1,7 +1,12 @@
module Ahoy
class Engine < ::Rails::Engine
- initializer "ahoy.middleware", after: "sprockets.environment" do
+ initializer "ahoy.middleware", after: "sprockets.environment" do |app|
Rails::Rack::Logger.send(:prepend, Ahoy::LogSilencer) if Ahoy.quiet
+
+ if Ahoy.throttle
+ require "ahoy/throttle"
+ app.middleware.use Ahoy::Throttle
+ end
end
end
end
ahoy/throttle.rb b/lib/ahoy/throttle.rb +17 -0
@@ @@ -0,0 +1,17 @@
+ require "rack/attack"
+
+ module Ahoy
+ class Throttle < Rack::Attack
+ throttle("ahoy/ip", limit: Ahoy.throttle_limit, period: Ahoy.throttle_period) do |req|
+ if req.path.start_with?("/ahoy/")
+ req.ip
+ end
+ end
+
+ def_delegators self, :whitelisted?, :blacklisted?, :throttled?, :tracked?
+
+ def self.throttled_response
+ Rack::Attack.throttled_response
+ end
+ end
+ end