Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-01-08 00:10:18 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-01-08 00:10:18 +0300
commitfd320d0858df108b47ebadaa546a3c99f0e44cf1 (patch)
tree10fd76baeaf079ba50392d569c52d3d711169c8b /lib/gitlab/rack_attack.rb
parentdec7332357ae21be289ac26a4c440cb0b5fa1002 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab/rack_attack.rb')
-rw-r--r--lib/gitlab/rack_attack.rb59
1 files changed, 53 insertions, 6 deletions
diff --git a/lib/gitlab/rack_attack.rb b/lib/gitlab/rack_attack.rb
index b136023d5f2..0595d0a7e5b 100644
--- a/lib/gitlab/rack_attack.rb
+++ b/lib/gitlab/rack_attack.rb
@@ -13,12 +13,10 @@ module Gitlab
# This is Rack::Attack::DEFAULT_THROTTLED_RESPONSE, modified to allow a custom response
Rack::Attack.throttled_response = lambda do |env|
- # Send the Retry-After header so clients (e.g. python-gitlab) can make good choices about delays
- match_data = env['rack.attack.match_data']
- now = match_data[:epoch_time]
- retry_after = match_data[:period] - (now % match_data[:period])
-
- [429, { 'Content-Type' => 'text/plain', 'Retry-After' => retry_after.to_s }, [Gitlab::Throttle.rate_limiting_response_text]]
+ throttled_headers = Gitlab::RackAttack.throttled_response_headers(
+ env['rack.attack.matched'], env['rack.attack.match_data']
+ )
+ [429, { 'Content-Type' => 'text/plain' }.merge(throttled_headers), [Gitlab::Throttle.rate_limiting_response_text]]
end
# Configure the throttles
@@ -27,6 +25,55 @@ module Gitlab
configure_user_allowlist
end
+ # Rate Limit HTTP headers are not standardized anywhere. This is the latest
+ # draft submitted to IETF:
+ # https://github.com/ietf-wg-httpapi/ratelimit-headers/blob/main/draft-ietf-httpapi-ratelimit-headers.md
+ #
+ # This method implement the most viable parts of the headers. Those headers
+ # will be sent back to the client when it gets throttled.
+ #
+ # - RateLimit-Limit: indicates the request quota associated to the client
+ # in 60 seconds. The time window for the quota here is supposed to be
+ # mirrored to throttle_*_period_in_seconds application settings. However,
+ # our HAProxy as well as some ecosystem libraries are using a fixed
+ # 60-second window. Therefore, the returned limit is approximately rounded
+ # up to fit into that window.
+ #
+ # - RateLimit-Observed: indicates the current request amount associated to
+ # the client within the time window.
+ #
+ # - RateLimit-Remaining: indicates the remaining quota within the time
+ # window. It is the result of RateLimit-Limit - RateLimit-Remaining
+ #
+ # - Retry-After: the remaining duration in seconds until the quota is
+ # reset. This is a standardized HTTP header:
+ # https://tools.ietf.org/html/rfc7231#page-69
+ #
+ # - RateLimit-Reset: Similar to Retry-After.
+ #
+ # - RateLimit-ResetTime: the point of time that the quest quota is reset.
+ def self.throttled_response_headers(matched, match_data)
+ # Match data example:
+ # {:discriminator=>"127.0.0.1", :count=>12, :period=>60 seconds, :limit=>1, :epoch_time=>1609833930}
+ # Source: https://github.com/rack/rack-attack/blob/v6.3.0/lib/rack/attack/throttle.rb#L33
+ period = match_data[:period]
+ limit = match_data[:limit]
+ rounded_limit = (limit.to_f * 1.minute / match_data[:period]).ceil
+ observed = match_data[:count]
+ now = match_data[:epoch_time]
+ retry_after = period - (now % period)
+ reset_time = now + (period - now % period)
+ {
+ 'RateLimit-Name' => matched.to_s,
+ 'RateLimit-Limit' => rounded_limit.to_s,
+ 'RateLimit-Observed' => observed.to_s,
+ 'RateLimit-Remaining' => (limit > observed ? limit - observed : 0).to_s,
+ 'RateLimit-Reset' => retry_after.to_s,
+ 'RateLimit-ResetTime' => Time.at(reset_time).httpdate,
+ 'Retry-After' => retry_after.to_s
+ }
+ end
+
def self.configure_user_allowlist
@user_allowlist = nil
user_allowlist