From 8e4b3d1ef7afb350e556ed57012daf6e04af8449 Mon Sep 17 00:00:00 2001 From: tamirms Date: Wed, 5 Jan 2022 12:29:40 +0000 Subject: [PATCH 1/2] Exempt SSE requests from rate limiting middleware --- services/horizon/internal/httpx/router.go | 14 +++++++++++++- services/horizon/internal/middleware_test.go | 7 +++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/services/horizon/internal/httpx/router.go b/services/horizon/internal/httpx/router.go index 922f5ac7af..d78042a7cc 100644 --- a/services/horizon/internal/httpx/router.go +++ b/services/horizon/internal/httpx/router.go @@ -19,6 +19,7 @@ import ( "github.com/stellar/go/services/horizon/internal/db2/history" "github.com/stellar/go/services/horizon/internal/ledger" "github.com/stellar/go/services/horizon/internal/paths" + "github.com/stellar/go/services/horizon/internal/render" "github.com/stellar/go/services/horizon/internal/render/sse" "github.com/stellar/go/services/horizon/internal/txsub" "github.com/stellar/go/support/db" @@ -97,7 +98,18 @@ func (r *Router) addMiddleware(config *RouterConfig, r.Use(c.Handler) if rateLimitter != nil { - r.Use(rateLimitter.RateLimit) + r.Use(func(handler http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Exempt streaming requests from rate limits via the HTTP middleware + // because rate limiting for streaming requests are already implemented in + // StreamHandler.ServeStream(). + if render.Negotiate(r) == render.MimeEventStream { + handler.ServeHTTP(w, r) + return + } + rateLimitter.RateLimit(handler).ServeHTTP(w, r) + }) + }) } if config.PrimaryDBSession != nil { diff --git a/services/horizon/internal/middleware_test.go b/services/horizon/internal/middleware_test.go index c6b617c2b3..22544caa86 100644 --- a/services/horizon/internal/middleware_test.go +++ b/services/horizon/internal/middleware_test.go @@ -82,6 +82,12 @@ func (suite *RateLimitMiddlewareTestSuite) TestRateLimit_LimitHeaders() { // Sets X-RateLimit-Remaining headers correctly. func (suite *RateLimitMiddlewareTestSuite) TestRateLimit_RemainingHeaders() { + // test that SSE requests are ignored + for i := 0; i < 10; i++ { + w := suite.rh.Get("/", test.RequestHelperStreaming) + assert.Equal(suite.T(), "", w.Header().Get("X-RateLimit-Remaining")) + } + for i := 0; i < 10; i++ { w := suite.rh.Get("/") expected := 10 - (i + 1) @@ -92,6 +98,7 @@ func (suite *RateLimitMiddlewareTestSuite) TestRateLimit_RemainingHeaders() { for i := 0; i < 10; i++ { w := suite.rh.Get("/") assert.Equal(suite.T(), "0", w.Header().Get("X-RateLimit-Remaining")) + assert.Equal(suite.T(), http.StatusTooManyRequests, w.Code) } } From a9a78b60e4eb552d2bf011914439307166863ae0 Mon Sep 17 00:00:00 2001 From: tamirms Date: Thu, 6 Jan 2022 07:58:41 +0000 Subject: [PATCH 2/2] Add extra assertion --- services/horizon/internal/middleware_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/horizon/internal/middleware_test.go b/services/horizon/internal/middleware_test.go index 22544caa86..b44d2cade6 100644 --- a/services/horizon/internal/middleware_test.go +++ b/services/horizon/internal/middleware_test.go @@ -86,12 +86,14 @@ func (suite *RateLimitMiddlewareTestSuite) TestRateLimit_RemainingHeaders() { for i := 0; i < 10; i++ { w := suite.rh.Get("/", test.RequestHelperStreaming) assert.Equal(suite.T(), "", w.Header().Get("X-RateLimit-Remaining")) + assert.NotEqual(suite.T(), http.StatusTooManyRequests, w.Code) } for i := 0; i < 10; i++ { w := suite.rh.Get("/") expected := 10 - (i + 1) assert.Equal(suite.T(), strconv.Itoa(expected), w.Header().Get("X-RateLimit-Remaining")) + assert.NotEqual(suite.T(), http.StatusTooManyRequests, w.Code) } // confirm remaining stays at 0