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

Commit

Permalink
Remove SynapseRequest.get_user_agent (#9069)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
richvdh authored Jan 12, 2021
1 parent b161528 commit 2ec8ca5
Show file tree
Hide file tree
Showing 9 changed files with 29 additions and 26 deletions.
1 change: 1 addition & 0 deletions changelog.d/9069.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove `SynapseRequest.get_user_agent`.
3 changes: 2 additions & 1 deletion synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.appservice import ApplicationService
from synapse.events import EventBase
from synapse.http import get_request_user_agent
from synapse.http.site import SynapseRequest
from synapse.logging import opentracing as opentracing
from synapse.storage.databases.main.registration import TokenLookupResult
Expand Down Expand Up @@ -187,7 +188,7 @@ async def get_user_by_req(
"""
try:
ip_addr = self.hs.get_ip_from_request(request)
user_agent = request.get_user_agent("")
user_agent = get_request_user_agent(request)

access_token = self.get_access_token_from_request(request)

Expand Down
6 changes: 3 additions & 3 deletions synapse/handlers/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@
UserDeactivatedError,
)
from synapse.api.ratelimiting import Ratelimiter
from synapse.handlers._base import BaseHandler
from synapse.handlers.ui_auth import INTERACTIVE_AUTH_CHECKERS
from synapse.handlers.ui_auth.checkers import UserInteractiveAuthChecker
from synapse.http import get_request_user_agent
from synapse.http.server import finish_request, respond_with_html
from synapse.http.site import SynapseRequest
from synapse.logging.context import defer_to_thread
Expand All @@ -62,8 +64,6 @@
from synapse.util.msisdn import phone_number_to_msisdn
from synapse.util.threepids import canonicalise_email

from ._base import BaseHandler

if TYPE_CHECKING:
from synapse.app.homeserver import HomeServer

Expand Down Expand Up @@ -539,7 +539,7 @@ async def check_ui_auth(
# authentication flow.
await self.store.set_ui_auth_clientdict(sid, clientdict)

user_agent = request.get_user_agent("")
user_agent = get_request_user_agent(request)

await self.store.add_user_agent_ip_to_ui_auth_session(
session.session_id, user_agent, clientip
Expand Down
5 changes: 3 additions & 2 deletions synapse/handlers/sso.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from twisted.web.http import Request

from synapse.api.errors import Codes, RedirectException, SynapseError
from synapse.http import get_request_user_agent
from synapse.http.server import respond_with_html
from synapse.http.site import SynapseRequest
from synapse.types import JsonDict, UserID, contains_invalid_mxid_characters
Expand Down Expand Up @@ -362,7 +363,7 @@ async def complete_sso_login_request(
attributes,
auth_provider_id,
remote_user_id,
request.get_user_agent(""),
get_request_user_agent(request),
request.getClientIP(),
)

Expand Down Expand Up @@ -628,7 +629,7 @@ async def handle_submit_username_request(
attributes,
session.auth_provider_id,
session.remote_user_id,
request.get_user_agent(""),
get_request_user_agent(request),
request.getClientIP(),
)

Expand Down
15 changes: 15 additions & 0 deletions synapse/http/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from twisted.internet import task
from twisted.web.client import FileBodyProducer
from twisted.web.iweb import IRequest

from synapse.api.errors import SynapseError

Expand Down Expand Up @@ -50,3 +51,17 @@ def stopProducing(self):
FileBodyProducer.stopProducing(self)
except task.TaskStopped:
pass


def get_request_user_agent(request: IRequest, default: str = "") -> str:
"""Return the last User-Agent header, or the given default.
"""
# There could be raw utf-8 bytes in the User-Agent header.

# N.B. if you don't do this, the logger explodes cryptically
# with maximum recursion trying to log errors about
# the charset problem.
# c.f. https://github.com/matrix-org/synapse/issues/3471

h = request.getHeader(b"User-Agent")
return h.decode("ascii", "replace") if h else default
18 changes: 2 additions & 16 deletions synapse/http/site.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from twisted.web.server import Request, Site

from synapse.config.server import ListenerConfig
from synapse.http import redact_uri
from synapse.http import get_request_user_agent, redact_uri
from synapse.http.request_metrics import RequestMetrics, requests_counter
from synapse.logging.context import LoggingContext, PreserveLoggingContext
from synapse.types import Requester
Expand Down Expand Up @@ -113,15 +113,6 @@ def get_method(self):
method = self.method.decode("ascii")
return method

def get_user_agent(self, default: str) -> str:
"""Return the last User-Agent header, or the given default.
"""
user_agent = self.requestHeaders.getRawHeaders(b"User-Agent", [None])[-1]
if user_agent is None:
return default

return user_agent.decode("ascii", "replace")

def render(self, resrc):
# this is called once a Resource has been found to serve the request; in our
# case the Resource in question will normally be a JsonResource.
Expand Down Expand Up @@ -292,12 +283,7 @@ def _finished_processing(self):
# and can see that we're doing something wrong.
authenticated_entity = repr(self.requester) # type: ignore[unreachable]

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

code = str(self.code)
if not self.finished:
Expand Down
2 changes: 1 addition & 1 deletion tests/handlers/test_cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,4 @@ def test_map_cas_user_to_invalid_localpart(self):

def _mock_request():
"""Returns a mock which will stand in as a SynapseRequest"""
return Mock(spec=["getClientIP", "get_user_agent"])
return Mock(spec=["getClientIP", "getHeader"])
3 changes: 1 addition & 2 deletions tests/handlers/test_oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ def _build_callback_request(
"addCookie",
"requestHeaders",
"getClientIP",
"get_user_agent",
"getHeader",
]
)

Expand All @@ -1020,5 +1020,4 @@ def _build_callback_request(
request.args[b"code"] = [code.encode("utf-8")]
request.args[b"state"] = [state.encode("utf-8")]
request.getClientIP.return_value = ip_address
request.get_user_agent.return_value = user_agent
return request
2 changes: 1 addition & 1 deletion tests/handlers/test_saml.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,4 +262,4 @@ def test_map_saml_response_redirect(self):

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

0 comments on commit 2ec8ca5

Please sign in to comment.