class ActionLimiter::Middleware::IP

IP based rate limiting middleware

Public Class Methods

new(app, options = {}) click to toggle source

@private

# File lib/action_limiter/middleware/ip.rb, line 41
def initialize(app, options = {})
  @app = app
  @response_builder = options.fetch(:response_builder) { ResponseBuilder.new }
  @token_bucket = ActionLimiter::TokenBucket.new(
    period: options.fetch(:period, 1),
    size: options.fetch(:size, 100),
    namespace: options.fetch(:namespace, 'action_limiter/middleware/ip')
  )
end

Public Instance Methods

call(env) click to toggle source

@private

# File lib/action_limiter/middleware/ip.rb, line 53
def call(env)
  status, headers, body = _call(env)

  headers.merge!(create_rate_limit_headers(env))

  [status, headers, body]
end

Private Instance Methods

_call(env) click to toggle source
# File lib/action_limiter/middleware/ip.rb, line 63
def _call(env)
  remote_ip = env.fetch('action_dispatch.remote_ip')
  bucket_key = Digest::MD5.hexdigest(remote_ip.to_s)
  bucket = @token_bucket.increment(bucket_key, Time.now)

  env['action_limiter.ip_bucket'] = bucket

  if bucket.value > @token_bucket.size
    @response_builder.call(env)
  else
    @app.call(env)
  end
end
create_rate_limit_headers(env) click to toggle source
# File lib/action_limiter/middleware/ip.rb, line 77
def create_rate_limit_headers(env)
  bucket = env.fetch('action_limiter.ip_bucket')

  {
    'X-Request-Count' => bucket.value.to_s,
    'X-Request-Period' => @token_bucket.period.to_s,
    'X-Request-Limit' => @token_bucket.size.to_s
  }
end