rate_limit_headers.rb 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. # frozen_string_literal: true
  2. module RateLimitHeaders
  3. extend ActiveSupport::Concern
  4. class_methods do
  5. def override_rate_limit_headers(method_name, options = {})
  6. around_action(only: method_name, if: :current_account) do |_controller, block|
  7. begin
  8. block.call
  9. ensure
  10. rate_limiter = RateLimiter.new(current_account, options)
  11. rate_limit_headers = rate_limiter.to_headers
  12. response.headers.merge!(rate_limit_headers) unless response.headers['X-RateLimit-Remaining'].present? && rate_limit_headers['X-RateLimit-Remaining'].to_i > response.headers['X-RateLimit-Remaining'].to_i
  13. end
  14. end
  15. end
  16. end
  17. included do
  18. before_action :set_rate_limit_headers, if: :rate_limited_request?
  19. end
  20. private
  21. def set_rate_limit_headers
  22. apply_header_limit
  23. apply_header_remaining
  24. apply_header_reset
  25. end
  26. def rate_limited_request?
  27. !request.env['rack.attack.throttle_data'].nil?
  28. end
  29. def apply_header_limit
  30. response.headers['X-RateLimit-Limit'] = rate_limit_limit
  31. end
  32. def rate_limit_limit
  33. api_throttle_data[:limit].to_s
  34. end
  35. def apply_header_remaining
  36. response.headers['X-RateLimit-Remaining'] = rate_limit_remaining
  37. end
  38. def rate_limit_remaining
  39. (api_throttle_data[:limit] - api_throttle_data[:count]).to_s
  40. end
  41. def apply_header_reset
  42. response.headers['X-RateLimit-Reset'] = rate_limit_reset
  43. end
  44. def rate_limit_reset
  45. (request_time + reset_period_offset).iso8601(6)
  46. end
  47. def api_throttle_data
  48. most_limited_type, = request.env['rack.attack.throttle_data'].min_by { |_key, value| value[:limit] - value[:count] }
  49. request.env['rack.attack.throttle_data'][most_limited_type]
  50. end
  51. def request_time
  52. @_request_time ||= Time.now.utc
  53. end
  54. def reset_period_offset
  55. api_throttle_data[:period] - request_time.to_i % api_throttle_data[:period]
  56. end
  57. end