aboutsummaryrefslogtreecommitdiff
path: root/clientapi
diff options
context:
space:
mode:
authorTill <2353100+S7evinK@users.noreply.github.com>2023-05-30 15:27:11 +0200
committerGitHub <noreply@github.com>2023-05-30 15:27:11 +0200
commit3dcca4017cb919fb249784d9cf9b83ea60a77f15 (patch)
tree93f1dbacbcd01e72c829571b34f9d8fb0d3fa657 /clientapi
parentf956a8c1d9172f6bbfb9f7515feacd477a0e35f5 (diff)
Fix potential state reset when trying to join a room (#3040)
When trying to join a room in short sequence, it is possible that a state reset occurs. This fixes it by using `singleflight`.
Diffstat (limited to 'clientapi')
-rw-r--r--clientapi/routing/routing.go42
1 files changed, 34 insertions, 8 deletions
diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go
index 2a2fa665..d3f19cae 100644
--- a/clientapi/routing/routing.go
+++ b/clientapi/routing/routing.go
@@ -20,14 +20,16 @@ import (
"strings"
"github.com/gorilla/mux"
- "github.com/matrix-org/dendrite/setup/base"
- userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
"github.com/nats-io/nats.go"
"github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus"
+ "golang.org/x/sync/singleflight"
+
+ "github.com/matrix-org/dendrite/setup/base"
+ userapi "github.com/matrix-org/dendrite/userapi/api"
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/clientapi/api"
@@ -84,6 +86,14 @@ func Setup(
unstableFeatures["org.matrix."+msc] = true
}
+ // singleflight protects /join endpoints from being invoked
+ // multiple times from the same user and room, otherwise
+ // a state reset can occur. This also avoids unneeded
+ // state calculations.
+ // TODO: actually fix this in the roomserver, as there are
+ // possibly other ways that can result in a stat reset.
+ sf := singleflight.Group{}
+
if cfg.Matrix.WellKnownClientName != "" {
logrus.Infof("Setting m.homeserver base_url as %s at /.well-known/matrix/client", cfg.Matrix.WellKnownClientName)
wkMux.Handle("/client", httputil.MakeExternalAPI("wellknown", func(r *http.Request) util.JSONResponse {
@@ -264,9 +274,17 @@ func Setup(
if err != nil {
return util.ErrorResponse(err)
}
- return JoinRoomByIDOrAlias(
- req, device, rsAPI, userAPI, vars["roomIDOrAlias"],
- )
+ // Only execute a join for roomIDOrAlias and UserID once. If there is a join in progress
+ // it waits for it to complete and returns that result for subsequent requests.
+ resp, _, _ := sf.Do(vars["roomIDOrAlias"]+device.UserID, func() (any, error) {
+ return JoinRoomByIDOrAlias(
+ req, device, rsAPI, userAPI, vars["roomIDOrAlias"],
+ ), nil
+ })
+ // once all joins are processed, drop them from the cache. Further requests
+ // will be processed as usual.
+ sf.Forget(vars["roomIDOrAlias"] + device.UserID)
+ return resp.(util.JSONResponse)
}, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
@@ -300,9 +318,17 @@ func Setup(
if err != nil {
return util.ErrorResponse(err)
}
- return JoinRoomByIDOrAlias(
- req, device, rsAPI, userAPI, vars["roomID"],
- )
+ // Only execute a join for roomID and UserID once. If there is a join in progress
+ // it waits for it to complete and returns that result for subsequent requests.
+ resp, _, _ := sf.Do(vars["roomID"]+device.UserID, func() (any, error) {
+ return JoinRoomByIDOrAlias(
+ req, device, rsAPI, userAPI, vars["roomID"],
+ ), nil
+ })
+ // once all joins are processed, drop them from the cache. Further requests
+ // will be processed as usual.
+ sf.Forget(vars["roomID"] + device.UserID)
+ return resp.(util.JSONResponse)
}, httputil.WithAllowGuests()),
).Methods(http.MethodPost, http.MethodOptions)
v3mux.Handle("/rooms/{roomID}/leave",