mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-23 06:43:09 -06:00
Initial rate limiting
This commit is contained in:
parent
3b0774805c
commit
b2f61a31cd
|
|
@ -27,6 +27,7 @@ import (
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth"
|
"github.com/matrix-org/dendrite/clientapi/auth"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
||||||
federationsenderAPI "github.com/matrix-org/dendrite/federationsender/api"
|
federationsenderAPI "github.com/matrix-org/dendrite/federationsender/api"
|
||||||
userapi "github.com/matrix-org/dendrite/userapi/api"
|
userapi "github.com/matrix-org/dendrite/userapi/api"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -45,6 +46,10 @@ type BasicAuth struct {
|
||||||
Password string `yaml:"password"`
|
Password string `yaml:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var clientRateLimits sync.Map // device ID -> chan bool buffered
|
||||||
|
var clientRateLimitMaxRequests = 10
|
||||||
|
var clientRateLimitTimeIntervalMS = time.Millisecond * 500
|
||||||
|
|
||||||
// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which authenticates the request.
|
// MakeAuthAPI turns a util.JSONRequestHandler function into an http.Handler which authenticates the request.
|
||||||
func MakeAuthAPI(
|
func MakeAuthAPI(
|
||||||
metricsName string, userAPI userapi.UserInternalAPI,
|
metricsName string, userAPI userapi.UserInternalAPI,
|
||||||
|
|
@ -55,6 +60,28 @@ func MakeAuthAPI(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return *err
|
return *err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the user has got free resource slots for this request.
|
||||||
|
// If they don't then we'll return an error.
|
||||||
|
rateLimit, _ := clientRateLimits.LoadOrStore(device.ID, make(chan struct{}, clientRateLimitMaxRequests))
|
||||||
|
rateChan := rateLimit.(chan struct{})
|
||||||
|
select {
|
||||||
|
case rateChan <- struct{}{}:
|
||||||
|
default:
|
||||||
|
// We hit the rate limit. Tell the client to back off.
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusTooManyRequests,
|
||||||
|
JSON: jsonerror.LimitExceeded("You are sending too many requests too quickly!", clientRateLimitTimeIntervalMS.Milliseconds()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// After the time interval, drain a resource from the rate limiting
|
||||||
|
// channel. This will free up space in the channel for new requests.
|
||||||
|
go func() {
|
||||||
|
<-time.After(clientRateLimitTimeIntervalMS)
|
||||||
|
<-rateChan
|
||||||
|
}()
|
||||||
|
|
||||||
// add the user ID to the logger
|
// add the user ID to the logger
|
||||||
logger := util.GetLogger((req.Context()))
|
logger := util.GetLogger((req.Context()))
|
||||||
logger = logger.WithField("user_id", device.UserID)
|
logger = logger.WithField("user_id", device.UserID)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue