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

Commit 0b684b5

Browse files
authored
Fix logging of incorrect status codes for disconnected requests (#12580)
The status code of requests must always be set, regardless of client disconnection, otherwise they will always be logged as 200!. Broken for `respond_with_json` in f48792e. Broken for `respond_with_json_bytes` in 3e58ce7. Broken for `respond_with_html_bytes` in ea26e9a. Signed-off-by: Sean Quah <[email protected]>
1 parent 629aa51 commit 0b684b5

File tree

4 files changed

+36
-5
lines changed

4 files changed

+36
-5
lines changed

changelog.d/12580.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a long standing bug where status codes would almost always get logged as 200!, irrespective of the actual status code, when clients disconnect before a request has finished processing.

synapse/http/server.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,9 @@ def respond_with_json(
683683
Returns:
684684
twisted.web.server.NOT_DONE_YET if the request is still active.
685685
"""
686+
# The response code must always be set, for logging purposes.
687+
request.setResponseCode(code)
688+
686689
# could alternatively use request.notifyFinish() and flip a flag when
687690
# the Deferred fires, but since the flag is RIGHT THERE it seems like
688691
# a waste.
@@ -697,7 +700,6 @@ def respond_with_json(
697700
else:
698701
encoder = _encode_json_bytes
699702

700-
request.setResponseCode(code)
701703
request.setHeader(b"Content-Type", b"application/json")
702704
request.setHeader(b"Cache-Control", b"no-cache, no-store, must-revalidate")
703705

@@ -728,13 +730,15 @@ def respond_with_json_bytes(
728730
Returns:
729731
twisted.web.server.NOT_DONE_YET if the request is still active.
730732
"""
733+
# The response code must always be set, for logging purposes.
734+
request.setResponseCode(code)
735+
731736
if request._disconnected:
732737
logger.warning(
733738
"Not sending response to request %s, already disconnected.", request
734739
)
735740
return None
736741

737-
request.setResponseCode(code)
738742
request.setHeader(b"Content-Type", b"application/json")
739743
request.setHeader(b"Content-Length", b"%d" % (len(json_bytes),))
740744
request.setHeader(b"Cache-Control", b"no-cache, no-store, must-revalidate")
@@ -840,6 +844,9 @@ def respond_with_html_bytes(request: Request, code: int, html_bytes: bytes) -> N
840844
code: The HTTP response code.
841845
html_bytes: The HTML bytes to use as the response body.
842846
"""
847+
# The response code must always be set, for logging purposes.
848+
request.setResponseCode(code)
849+
843850
# could alternatively use request.notifyFinish() and flip a flag when
844851
# the Deferred fires, but since the flag is RIGHT THERE it seems like
845852
# a waste.
@@ -849,7 +856,6 @@ def respond_with_html_bytes(request: Request, code: int, html_bytes: bytes) -> N
849856
)
850857
return None
851858

852-
request.setResponseCode(code)
853859
request.setHeader(b"Content-Type", b"text/html; charset=utf-8")
854860
request.setHeader(b"Content-Length", b"%d" % (len(html_bytes),))
855861

tests/handlers/test_cas.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -201,4 +201,16 @@ def test_required_attributes(self) -> None:
201201

202202
def _mock_request():
203203
"""Returns a mock which will stand in as a SynapseRequest"""
204-
return Mock(spec=["getClientIP", "getHeader", "_disconnected"])
204+
mock = Mock(
205+
spec=[
206+
"finish",
207+
"getClientIP",
208+
"getHeader",
209+
"setHeader",
210+
"setResponseCode",
211+
"write",
212+
]
213+
)
214+
# `_disconnected` musn't be another `Mock`, otherwise it will be truthy.
215+
mock._disconnected = False
216+
return mock

tests/handlers/test_saml.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,16 @@ def test_attribute_requirements(self) -> None:
349349

350350
def _mock_request():
351351
"""Returns a mock which will stand in as a SynapseRequest"""
352-
return Mock(spec=["getClientIP", "getHeader", "_disconnected"])
352+
mock = Mock(
353+
spec=[
354+
"finish",
355+
"getClientIP",
356+
"getHeader",
357+
"setHeader",
358+
"setResponseCode",
359+
"write",
360+
]
361+
)
362+
# `_disconnected` musn't be another `Mock`, otherwise it will be truthy.
363+
mock._disconnected = False
364+
return mock

0 commit comments

Comments
 (0)