diff options
author | Jaime Martinez <jmartinez@gitlab.com> | 2021-09-22 09:38:25 +0300 |
---|---|---|
committer | Jaime Martinez <jmartinez@gitlab.com> | 2021-10-14 08:59:51 +0300 |
commit | ccfdff303646b86daed2bd9ae7e2f2a5eb4a2c5c (patch) | |
tree | 81bc3444ad0417cd4454077fd187323a292bfc93 /test/acceptance | |
parent | 247bd7ba2fd9139711218c6a42ed03c551f958d9 (diff) |
feat: add source IP ratelimiter middleware
It gets the source IP from `r.RemoteAddr` or from the `X-Forwarded-For`
header for proxied requests (when `--listen-proxy` is enabled).
The first iteration will only report logs and metrics when an IP is
being rate limited.
The rate limiter uses a Token Bucket approach using
golang.org/x/time/rate, which can be configured with the newly added
flags `rate-limit-source-ip` and `rate-limit-source-ip-burst`.
To enable the rate limiter, set `rate-limit-source-ip` to value > 1,
which is the number of requests per second to allow. It is enabled by
default in "dry-run" mode so requests won't be dropped until the
environment variable
`FF_ENABLE_RATE_LIMITER` is set to `"true"`.
See metrics.go for the newly added metrics.
Changelog: added
Diffstat (limited to 'test/acceptance')
-rw-r--r-- | test/acceptance/ratelimiter_test.go | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/test/acceptance/ratelimiter_test.go b/test/acceptance/ratelimiter_test.go new file mode 100644 index 00000000..d67b3d04 --- /dev/null +++ b/test/acceptance/ratelimiter_test.go @@ -0,0 +1,39 @@ +package acceptance_test + +import ( + "net/http" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "gitlab.com/gitlab-org/gitlab-pages/internal/testhelpers" +) + +func TestRateLimitMiddleware(t *testing.T) { + testhelpers.EnableRateLimiter(t) + + RunPagesProcess(t, + withListeners([]ListenSpec{httpListener}), + // 10 = 1 req every 100ms + withExtraArgument("rate-limit-source-ip", "1.0"), + withExtraArgument("rate-limit-source-ip-burst", "1"), + ) + + for i := 0; i < 20; i++ { + rsp1, err := GetPageFromListener(t, httpListener, "group.gitlab-example.com", "project/") + require.NoError(t, err) + rsp1.Body.Close() + + // every other request should fail + //if i%2 != 0 { + // require.Equal(t, http.StatusTooManyRequests, rsp1.StatusCode, "group.gitlab-example.com request: %d failed", i) + // // wait for another token to become available + // time.Sleep(100 * time.Millisecond) + // continue + //} + + require.Equal(t, http.StatusOK, rsp1.StatusCode, "group.gitlab-example.com request: %d failed", i) + time.Sleep(time.Millisecond) + } +} |