FEATURE: set 'Retry-After' header for 429 responses (#5659)

This commit is contained in:
Kyle Zhao 2018-03-13 11:12:41 -04:00 committed by Guo Xiang Tan
parent 9b651adadb
commit f7bd05e534
3 changed files with 18 additions and 6 deletions

View File

@ -107,7 +107,15 @@ class ApplicationController < ActionController::Base
end
def render_rate_limit_error(e)
render_json_error e.description, type: :rate_limit, status: 429, extras: { wait_seconds: e&.available_in }
retry_time_in_seconds = e&.available_in
render_json_error(
e.description,
type: :rate_limit,
status: 429,
extras: { wait_seconds: retry_time_in_seconds },
headers: { 'Retry-After': retry_time_in_seconds },
)
end
# If they hit the rate limiter
@ -523,12 +531,15 @@ class ApplicationController < ActionController::Base
# Render action for a JSON error.
#
# obj - a translated string, an ActiveRecord model, or an array of translated strings
# obj - a translated string, an ActiveRecord model, or an array of translated strings
# opts:
# type - a machine-readable description of the error
# status - HTTP status code to return
# type - a machine-readable description of the error
# status - HTTP status code to return
# headers - extra headers for the response
def render_json_error(obj, opts = {})
opts = { status: opts } if opts.is_a?(Integer)
opts.fetch(:headers, {}).each { |name, value| headers[name.to_s] = value }
render json: MultiJson.dump(create_errors_json(obj, opts)), status: opts[:status] || 422
end

View File

@ -70,7 +70,7 @@ MessageBus.on_middleware_error do |env, e|
if Discourse::InvalidAccess === e
[403, {}, ["Invalid Access"]]
elsif RateLimiter::LimitExceeded === e
[429, {}, [e.description]]
[429, { 'Retry-After' => e.available_in }, [e.description]]
end
end

View File

@ -25,7 +25,7 @@ describe 'rate limiter integration' do
}
end
it 'can cleanly limit requests' do
it 'can cleanly limit requests and sets a Retry-After header' do
freeze_time
#request.set_header("action_dispatch.show_exceptions", true)
@ -50,6 +50,7 @@ describe 'rate limiter integration' do
data = JSON.parse(response.body)
expect(response.headers['Retry-After']).to eq(60)
expect(data["extras"]["wait_seconds"]).to eq(60)
end
end