Class: Gitlab::Middleware::RackAttackHeaders

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/middleware/rack_attack_headers.rb

Overview

Rack middleware that adds rate limit headers to all responses processed by Rack::Attack.

Unlike the default Rack::Attack behavior (which only adds headers to throttled requests), this middleware adds rate limit headers to ALL requests that have throttle data available and are not already rate-limited (i.e. HTTP status 429). This enables clients to proactively adjust their request rates before hitting limits, improving the overall user experience and reducing unnecessary 429 errors.

Integrates with RackAttack::RequestThrottleData to generate standardized rate limit headers.

When multiple throttles apply to a request, the most restrictive one (lowest remaining quota) is used for the headers.

Examples:

Typical request flow

# Request comes in -> Rack::Attack processes it -> This middleware adds headers
# Response: 200 OK
# Headers: RateLimit-Limit: 100, RateLimit-Remaining: 75, RateLimit-Reset: 1234567890, etc.

See Also:

Constant Summary collapse

RACK_ATTACK_THROTTLE_DATA_KEY =

Rack environment key where Rack::Attack stores throttle data

'rack.attack.throttle_data'

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ RackAttackHeaders

Initialize the middleware

Parameters:

  • The Rack application



33
34
35
# File 'lib/gitlab/middleware/rack_attack_headers.rb', line 33

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Array<Integer, Hash, Object>

Process the request and add rate limit headers if applicable

Parameters:

  • The Rack environment

Returns:

  • Standard Rack response tuple (status, headers, body)



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/gitlab/middleware/rack_attack_headers.rb', line 41

def call(env)
  status, headers, body = @app.call(env)

  # Add rate limit headers if Rack::Attack has throttle data
  if should_add_headers?(env, status)
    rate_limit_headers = generate_headers(env)
    headers.merge!(rate_limit_headers) if rate_limit_headers.present?
  end

  [status, headers, body]
end