Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 2ec8ca5

Browse files
authored
Remove SynapseRequest.get_user_agent (#9069)
SynapseRequest is in danger of becoming a bit of a dumping-ground for "useful stuff relating to Requests", which isn't really its intention (its purpose is to override render, finished and connectionLost to set up the LoggingContext and write the right entries to the request log). Putting utility functions inside SynapseRequest means that lots of our code ends up requiring a SynapseRequest when there is nothing synapse-specific about the Request at all, and any old twisted.web.iweb.IRequest will do. This increases code coupling and makes testing more difficult. In short: move get_user_agent out to a utility function.
1 parent b161528 commit 2ec8ca5

File tree

9 files changed

+29
-26
lines changed

9 files changed

+29
-26
lines changed

changelog.d/9069.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove `SynapseRequest.get_user_agent`.

synapse/api/auth.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
3434
from synapse.appservice import ApplicationService
3535
from synapse.events import EventBase
36+
from synapse.http import get_request_user_agent
3637
from synapse.http.site import SynapseRequest
3738
from synapse.logging import opentracing as opentracing
3839
from synapse.storage.databases.main.registration import TokenLookupResult
@@ -187,7 +188,7 @@ async def get_user_by_req(
187188
"""
188189
try:
189190
ip_addr = self.hs.get_ip_from_request(request)
190-
user_agent = request.get_user_agent("")
191+
user_agent = get_request_user_agent(request)
191192

192193
access_token = self.get_access_token_from_request(request)
193194

synapse/handlers/auth.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@
4949
UserDeactivatedError,
5050
)
5151
from synapse.api.ratelimiting import Ratelimiter
52+
from synapse.handlers._base import BaseHandler
5253
from synapse.handlers.ui_auth import INTERACTIVE_AUTH_CHECKERS
5354
from synapse.handlers.ui_auth.checkers import UserInteractiveAuthChecker
55+
from synapse.http import get_request_user_agent
5456
from synapse.http.server import finish_request, respond_with_html
5557
from synapse.http.site import SynapseRequest
5658
from synapse.logging.context import defer_to_thread
@@ -62,8 +64,6 @@
6264
from synapse.util.msisdn import phone_number_to_msisdn
6365
from synapse.util.threepids import canonicalise_email
6466

65-
from ._base import BaseHandler
66-
6767
if TYPE_CHECKING:
6868
from synapse.app.homeserver import HomeServer
6969

@@ -539,7 +539,7 @@ async def check_ui_auth(
539539
# authentication flow.
540540
await self.store.set_ui_auth_clientdict(sid, clientdict)
541541

542-
user_agent = request.get_user_agent("")
542+
user_agent = get_request_user_agent(request)
543543

544544
await self.store.add_user_agent_ip_to_ui_auth_session(
545545
session.session_id, user_agent, clientip

synapse/handlers/sso.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from twisted.web.http import Request
2424

2525
from synapse.api.errors import Codes, RedirectException, SynapseError
26+
from synapse.http import get_request_user_agent
2627
from synapse.http.server import respond_with_html
2728
from synapse.http.site import SynapseRequest
2829
from synapse.types import JsonDict, UserID, contains_invalid_mxid_characters
@@ -362,7 +363,7 @@ async def complete_sso_login_request(
362363
attributes,
363364
auth_provider_id,
364365
remote_user_id,
365-
request.get_user_agent(""),
366+
get_request_user_agent(request),
366367
request.getClientIP(),
367368
)
368369

@@ -628,7 +629,7 @@ async def handle_submit_username_request(
628629
attributes,
629630
session.auth_provider_id,
630631
session.remote_user_id,
631-
request.get_user_agent(""),
632+
get_request_user_agent(request),
632633
request.getClientIP(),
633634
)
634635

synapse/http/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
from twisted.internet import task
1919
from twisted.web.client import FileBodyProducer
20+
from twisted.web.iweb import IRequest
2021

2122
from synapse.api.errors import SynapseError
2223

@@ -50,3 +51,17 @@ def stopProducing(self):
5051
FileBodyProducer.stopProducing(self)
5152
except task.TaskStopped:
5253
pass
54+
55+
56+
def get_request_user_agent(request: IRequest, default: str = "") -> str:
57+
"""Return the last User-Agent header, or the given default.
58+
"""
59+
# There could be raw utf-8 bytes in the User-Agent header.
60+
61+
# N.B. if you don't do this, the logger explodes cryptically
62+
# with maximum recursion trying to log errors about
63+
# the charset problem.
64+
# c.f. https://github.com/matrix-org/synapse/issues/3471
65+
66+
h = request.getHeader(b"User-Agent")
67+
return h.decode("ascii", "replace") if h else default

synapse/http/site.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from twisted.web.server import Request, Site
2121

2222
from synapse.config.server import ListenerConfig
23-
from synapse.http import redact_uri
23+
from synapse.http import get_request_user_agent, redact_uri
2424
from synapse.http.request_metrics import RequestMetrics, requests_counter
2525
from synapse.logging.context import LoggingContext, PreserveLoggingContext
2626
from synapse.types import Requester
@@ -113,15 +113,6 @@ def get_method(self):
113113
method = self.method.decode("ascii")
114114
return method
115115

116-
def get_user_agent(self, default: str) -> str:
117-
"""Return the last User-Agent header, or the given default.
118-
"""
119-
user_agent = self.requestHeaders.getRawHeaders(b"User-Agent", [None])[-1]
120-
if user_agent is None:
121-
return default
122-
123-
return user_agent.decode("ascii", "replace")
124-
125116
def render(self, resrc):
126117
# this is called once a Resource has been found to serve the request; in our
127118
# case the Resource in question will normally be a JsonResource.
@@ -292,12 +283,7 @@ def _finished_processing(self):
292283
# and can see that we're doing something wrong.
293284
authenticated_entity = repr(self.requester) # type: ignore[unreachable]
294285

295-
# ...or could be raw utf-8 bytes in the User-Agent header.
296-
# N.B. if you don't do this, the logger explodes cryptically
297-
# with maximum recursion trying to log errors about
298-
# the charset problem.
299-
# c.f. https://github.com/matrix-org/synapse/issues/3471
300-
user_agent = self.get_user_agent("-")
286+
user_agent = get_request_user_agent(self, "-")
301287

302288
code = str(self.code)
303289
if not self.finished:

tests/handlers/test_cas.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,4 @@ def test_map_cas_user_to_invalid_localpart(self):
118118

119119
def _mock_request():
120120
"""Returns a mock which will stand in as a SynapseRequest"""
121-
return Mock(spec=["getClientIP", "get_user_agent"])
121+
return Mock(spec=["getClientIP", "getHeader"])

tests/handlers/test_oidc.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@ def _build_callback_request(
10111011
"addCookie",
10121012
"requestHeaders",
10131013
"getClientIP",
1014-
"get_user_agent",
1014+
"getHeader",
10151015
]
10161016
)
10171017

@@ -1020,5 +1020,4 @@ def _build_callback_request(
10201020
request.args[b"code"] = [code.encode("utf-8")]
10211021
request.args[b"state"] = [state.encode("utf-8")]
10221022
request.getClientIP.return_value = ip_address
1023-
request.get_user_agent.return_value = user_agent
10241023
return request

tests/handlers/test_saml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,4 +262,4 @@ def test_map_saml_response_redirect(self):
262262

263263
def _mock_request():
264264
"""Returns a mock which will stand in as a SynapseRequest"""
265-
return Mock(spec=["getClientIP", "get_user_agent"])
265+
return Mock(spec=["getClientIP", "getHeader"])

0 commit comments

Comments
 (0)