diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ed7b9fba4a..3e14d07e22 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -60,9 +60,10 @@ jobs: - 'poetry.lock' - 'docker/**' - '.ci/**' - - 'scripts-dev/complement.sh' - '.github/workflows/tests.yml' + - 'scripts-dev/complement.sh' - '.github/workflows/complement_tests.yml' + - 'complement/**' linting: - 'synapse/**' diff --git a/changelog.d/19855.bugfix b/changelog.d/19855.bugfix new file mode 100644 index 0000000000..706f779174 --- /dev/null +++ b/changelog.d/19855.bugfix @@ -0,0 +1 @@ +Provide remote servers a way to find out about an event created during the remote join handshake. Contributed by @FrenchGithubUser and @jason-famedly @ Famedly. diff --git a/complement/tests/federation_room_join_test.go b/complement/tests/federation_room_join_test.go index 7ed1f93f87..767c6d7ca9 100644 --- a/complement/tests/federation_room_join_test.go +++ b/complement/tests/federation_room_join_test.go @@ -68,53 +68,56 @@ func TestEventBetweenMakeJoinAndSendJoinIsNotLost(t *testing.T) { // Complement server is not fully in the room until send_join completes, so // we can't use HandleTransactionRequests (which requires the room in // srv.rooms). Instead we parse the raw transaction body ourselves. - srv.Mux().Handle("/_matrix/federation/v1/send/{transactionID}", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - body, err := io.ReadAll(req.Body) - must.NotError(t, "failed to read request body in /send handler: %v", err) - txn := gjson.ParseBytes(body) - txn.Get("pdus").ForEach(func(_, pdu gjson.Result) bool { - eventID := pdu.Get("event_id").String() - eventType := pdu.Get("type").String() - t.Logf("Received PDU via /send: type=%s id=%s", eventType, eventID) + srv.Mux(). + Handle("/_matrix/federation/v1/send/{transactionID}", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + body, err := io.ReadAll(req.Body) + must.NotError(t, "failed to read request body in /send handler: %v", err) + txn := gjson.ParseBytes(body) + txn.Get("pdus").ForEach(func(_, pdu gjson.Result) bool { + eventID := pdu.Get("event_id").String() + eventType := pdu.Get("type").String() + t.Logf("Received PDU via /send: type=%s id=%s", eventType, eventID) - // messageEventID is set after make_join but before send_join. - // Transactions can arrive before that window, so skip PDUs that - // arrive before we know which event to look for. - msgID, _ := messageEventID.Load().(string) - if msgID == "" { - return true - } - - // Check if this IS the message event (server pushed it directly). - if eventID == msgID { - messageDiscoverableWaiter.Finish() - return true - } - - // Check if this event's prev_events directly reference the message (e.g. a dummy - // event tying the two forward extremities together). If so, the joining server - // can backfill from that event and will discover the message. - // - // XXX: We only check one level of prev_events: if the reference is deeper in the - // DAG, it's valid and the joining server can still reach the message through - // backfill but our checks don't account for that yet (feel free to edit this - // assertion if you run into this) - pdu.Get("prev_events").ForEach(func(_, prevEvent gjson.Result) bool { - if prevEvent.String() == msgID { - messageDiscoverableWaiter.Finish() - return false + // messageEventID is set after make_join but before send_join. + // Transactions can arrive before that window, so skip PDUs that + // arrive before we know which event to look for. + msgID, _ := messageEventID.Load().(string) + if msgID == "" { + return true } + + // Check if this IS the message event (server pushed it directly). + if eventID == msgID { + messageDiscoverableWaiter.Finish() + return true + } + + // Check if this event's prev_events directly reference the message (e.g. a dummy + // event tying the two forward extremities together). If so, the joining server + // can backfill from that event and will discover the message. + // + // XXX: We only check one level of prev_events: if the reference is deeper in the + // DAG, it's valid and the joining server can still reach the message through + // backfill but our checks don't account for that yet (feel free to edit this + // assertion if you run into this) + pdu.Get("prev_events").ForEach(func(_, prevEvent gjson.Result) bool { + if prevEvent.String() == msgID { + messageDiscoverableWaiter.Finish() + return false + } + return true + }) + return true }) - - return true - }) - w.WriteHeader(200) - // Respond with an empty PDU error map, which is the federation /send - // success response format: each key would be a PDU ID whose processing - // failed; an empty object means all PDUs were accepted. - w.Write([]byte(`{"pdus":{}}`)) - })).Methods("PUT") + w.WriteHeader(200) + // Respond with an empty PDU error map, which is the federation /send + // success response format: each key would be a PDU ID whose processing + // failed; an empty object means all PDUs were accepted. + _, err = w.Write([]byte(`{"pdus":{}}`)) + must.NotError(t, "failed to write response body in /send handler: %v", err) + })). + Methods("PUT") cancel := srv.Listen() defer cancel()