class Rack::Attack::Throttle

Constants

MANDATORY_OPTIONS

Attributes

block[R]
limit[R]
name[R]
period[R]
type[R]

Public Class Methods

new(name, options, &block) click to toggle source
# File lib/rack/attack/throttle.rb, line 10
def initialize(name, options, &block)
  @name = name
  @block = block
  MANDATORY_OPTIONS.each do |opt|
    raise ArgumentError, "Must pass #{opt.inspect} option" unless options[opt]
  end
  @limit = options[:limit]
  @period = options[:period].respond_to?(:call) ? options[:period] : options[:period].to_i
  @type   = options.fetch(:type, :throttle)
end

Public Instance Methods

cache() click to toggle source
# File lib/rack/attack/throttle.rb, line 21
def cache
  Rack::Attack.cache
end
matched_by?(request) click to toggle source
# File lib/rack/attack/throttle.rb, line 25
def matched_by?(request)
  discriminator = discriminator_for(request)
  return false unless discriminator

  current_period  = period_for(request)
  current_limit   = limit_for(request)
  count           = cache.count("#{name}:#{discriminator}", current_period)

  data = {
    discriminator: discriminator,
    count: count,
    period: current_period,
    limit: current_limit,
    epoch_time: cache.last_epoch_time
  }

  (count > current_limit).tap do |throttled|
    annotate_request_with_throttle_data(request, data)
    if throttled
      annotate_request_with_matched_data(request, data)
      Rack::Attack.instrument(request)
    end
  end
end

Private Instance Methods

annotate_request_with_matched_data(request, data) click to toggle source
# File lib/rack/attack/throttle.rb, line 72
def annotate_request_with_matched_data(request, data)
  request.env['rack.attack.matched']             = name
  request.env['rack.attack.match_discriminator'] = data[:discriminator]
  request.env['rack.attack.match_type']          = type
  request.env['rack.attack.match_data']          = data
end
annotate_request_with_throttle_data(request, data) click to toggle source
# File lib/rack/attack/throttle.rb, line 68
def annotate_request_with_throttle_data(request, data)
  (request.env['rack.attack.throttle_data'] ||= {})[name] = data
end
discriminator_for(request) click to toggle source
# File lib/rack/attack/throttle.rb, line 52
def discriminator_for(request)
  discriminator = block.call(request)
  if discriminator && Rack::Attack.throttle_discriminator_normalizer
    discriminator = Rack::Attack.throttle_discriminator_normalizer.call(discriminator)
  end
  discriminator
end
limit_for(request) click to toggle source
# File lib/rack/attack/throttle.rb, line 64
def limit_for(request)
  limit.respond_to?(:call) ? limit.call(request) : limit
end
period_for(request) click to toggle source
# File lib/rack/attack/throttle.rb, line 60
def period_for(request)
  period.respond_to?(:call) ? period.call(request) : period
end