summary refs log tree commit diff
path: root/synapse
diff options
context:
space:
mode:
authorWill Hunt <will@half-shot.uk>2023-08-24 15:40:26 +0100
committerGitHub <noreply@github.com>2023-08-24 10:40:26 -0400
commit0538e3e2dba8ff5bbc13f11d796e696f6ba8a7c7 (patch)
treef40c44f233f4ec5ac5a17a91a63ced0458d69c84 /synapse
parentBump serde_json from 1.0.104 to 1.0.105 (#16140) (diff)
downloadsynapse-0538e3e2dba8ff5bbc13f11d796e696f6ba8a7c7.tar.xz
Add `Retry-After` to M_LIMIT_EXCEEDED error responses (#16136)
Implements MSC4041 behind an experimental configuration flag.
Diffstat (limited to 'synapse')
-rw-r--r--synapse/api/errors.py10
-rw-r--r--synapse/config/experimental.py9
2 files changed, 18 insertions, 1 deletions
diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index 7ffd72c42c..578e798773 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -16,6 +16,7 @@
 """Contains exceptions and error codes."""
 
 import logging
+import math
 import typing
 from enum import Enum
 from http import HTTPStatus
@@ -503,6 +504,8 @@ class InvalidCaptchaError(SynapseError):
 class LimitExceededError(SynapseError):
     """A client has sent too many requests and is being throttled."""
 
+    include_retry_after_header = False
+
     def __init__(
         self,
         code: int = 429,
@@ -510,7 +513,12 @@ class LimitExceededError(SynapseError):
         retry_after_ms: Optional[int] = None,
         errcode: str = Codes.LIMIT_EXCEEDED,
     ):
-        super().__init__(code, msg, errcode)
+        headers = (
+            {"Retry-After": str(math.ceil(retry_after_ms / 1000))}
+            if self.include_retry_after_header and retry_after_ms is not None
+            else None
+        )
+        super().__init__(code, msg, errcode, headers=headers)
         self.retry_after_ms = retry_after_ms
 
     def error_dict(self, config: Optional["HomeServerConfig"]) -> "JsonDict":
diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index 84d6dd13af..cabe0d4397 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.py
@@ -18,6 +18,7 @@ from typing import TYPE_CHECKING, Any, Optional
 import attr
 import attr.validators
 
+from synapse.api.errors import LimitExceededError
 from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersions
 from synapse.config import ConfigError
 from synapse.config._base import Config, RootConfig
@@ -406,3 +407,11 @@ class ExperimentalConfig(Config):
         self.msc4010_push_rules_account_data = experimental.get(
             "msc4010_push_rules_account_data", False
         )
+
+        # MSC4041: Use HTTP header Retry-After to enable library-assisted retry handling
+        #
+        # This is a bit hacky, but the most reasonable way to *alway* include the
+        # headers.
+        LimitExceededError.include_retry_after_header = experimental.get(
+            "msc4041_enabled", False
+        )