From aa976873056b1fccb4d3a63f2b2c915440304fac Mon Sep 17 00:00:00 2001 From: Andy Balaam Date: Tue, 30 Jun 2026 22:20:26 +0100 Subject: [PATCH] Change MSC3814 dehydrated device `/events` endpoint from POST to GET (#19896) Change `/org.matrix.msc3814.v1/dehydrated_device/[device_id]/events` to accept GET requests instead of POST. The original version of [MSC3814](https://github.com/matrix-org/matrix-spec-proposals/pull/3814) said we should delete keys after returning them from this endpoint, but it is being updated to say we should not delete them, and therefore the appropriate verb is GET. Synapse already doesn't delete anything, so we just need to change to a GET with a `next_batch` query param. (Currently it is a POST with `next_batch` in the JSON content.) This code was initially written by @ara4n and Claude, but both he and I have read it and think it makes sense. I am far from a Synapse expert, so feel free to tell me it's all wrong and point me in the right direction. I don't know what system tests will be affected by this, but I guess we will see when the CI runs (right?). This is a change to an unstable endpoint so no need for notifications about breaking changes or similar. Part of https://github.com/element-hq/element-meta/issues/2704 ### Pull Request Checklist * [x] Pull request is based on the develop branch * [x] Pull request includes a [changelog file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog). The entry should: * [x] [Code style](https://element-hq.github.io/synapse/latest/code_style.html) is correct (run the [linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters)) --------- Co-authored-by: Matthew Hodgson --- changelog.d/19896.misc | 1 + synapse/rest/client/devices.py | 33 +++++++++++++++++++++++++++++++ tests/rest/client/test_devices.py | 12 ++++------- 3 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 changelog.d/19896.misc diff --git a/changelog.d/19896.misc b/changelog.d/19896.misc new file mode 100644 index 0000000000..2c6a8740ef --- /dev/null +++ b/changelog.d/19896.misc @@ -0,0 +1 @@ +Change the [MSC3814](https://github.com/matrix-org/matrix-spec-proposals/pull/3814) dehydrated device `/events` endpoint from `POST` to `GET`. diff --git a/synapse/rest/client/devices.py b/synapse/rest/client/devices.py index 0231ed374d..76043e6120 100644 --- a/synapse/rest/client/devices.py +++ b/synapse/rest/client/devices.py @@ -33,6 +33,7 @@ from synapse.http.servlet import ( RestServlet, parse_and_validate_json_object_from_request, parse_integer, + parse_string, ) from synapse.http.site import SynapseRequest from synapse.rest.client._base import client_patterns, interactive_auth_handler @@ -249,17 +250,49 @@ class DehydratedDeviceEventsServlet(RestServlet): self.auth = hs.get_auth() self.store = hs.get_datastores().main + async def on_GET( + self, request: SynapseRequest, device_id: str + ) -> tuple[int, JsonDict]: + requester = await self.auth.get_user_by_req(request) + + next_batch = parse_string(request, "next_batch") + limit = parse_integer(request, "limit", 100) + + msgs = await self.message_handler.get_events_for_dehydrated_device( + requester=requester, + device_id=device_id, + since_token=next_batch, + limit=limit, + ) + + return 200, msgs + class PostBody(RequestBodyModel): + """ + This is deprecated: you should use GET instead. + + The POST version is provided temporarily for backwards compatibility + with a previous unstable draft of MSC3814. + """ + next_batch: StrictStr | None = None async def on_POST( self, request: SynapseRequest, device_id: str ) -> tuple[int, JsonDict]: + """ + This is deprecated: you should use GET instead. + + The POST version is provided temporarily for backwards compatibility + with a previous unstable draft of MSC3814. + """ + requester = await self.auth.get_user_by_req(request) next_batch = parse_and_validate_json_object_from_request( request, self.PostBody ).next_batch + limit = parse_integer(request, "limit", 100) msgs = await self.message_handler.get_events_for_dehydrated_device( diff --git a/tests/rest/client/test_devices.py b/tests/rest/client/test_devices.py index 2cf293a962..bdf9ad1786 100644 --- a/tests/rest/client/test_devices.py +++ b/tests/rest/client/test_devices.py @@ -224,9 +224,8 @@ class DehydratedDeviceTestCase(unittest.HomeserverTestCase): # make sure we can fetch the message with our dehydrated device id channel = self.make_request( - "POST", + "GET", f"_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device/{device_id}/events", - content={}, access_token=token, shorthand=False, ) @@ -236,9 +235,8 @@ class DehydratedDeviceTestCase(unittest.HomeserverTestCase): # fetch messages again and make sure that the message was not deleted channel = self.make_request( - "POST", + "GET", f"_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device/{device_id}/events", - content={}, access_token=token, shorthand=False, ) @@ -248,11 +246,9 @@ class DehydratedDeviceTestCase(unittest.HomeserverTestCase): # make sure fetching messages with next batch token works - there are no unfetched # messages so we should receive an empty array - content = {"next_batch": next_batch_token} channel = self.make_request( - "POST", - f"_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device/{device_id}/events", - content=content, + "GET", + f"_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device/{device_id}/events?next_batch={next_batch_token}", access_token=token, shorthand=False, )