Respond with useful error codes when Content-Length header/s are invalid (#19212)
Related to https://github.com/element-hq/synapse/issues/17035, when Synapse receives a request that is larger than the maximum size allowed, it aborts the connection without ever sending back a HTTP response. I dug into our usage of twisted and how best to try and report such an error and this is what I came up with. It would be ideal to be able to report the status from within `handleContentChunk` but that is called too early on in the twisted http handling code, before things have been setup enough to be able to properly write a response. I tested this change out locally (both with C-S and S-S apis) and they do receive a 413 response now in addition to the connection being closed. Hopefully this will aid in being able to quickly detect when https://github.com/element-hq/synapse/issues/17035 is occurring as the current situation makes it very hard to narrow things down to that specific issue without making a lot of assumptions. This PR also responds with more meaningful error codes now in the case of: - multiple `Content-Length` headers - invalid `Content-Length` header value - request content size being larger than the `Content-Length` value ### Pull Request Checklist <!-- Please read https://element-hq.github.io/synapse/latest/development/contributing_guide.html before submitting your pull request --> * [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: - Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from `EventStore` to `EventWorkerStore`.". - Use markdown where necessary, mostly for `code blocks`. - End with either a period (.) or an exclamation mark (!). - Start with a capital letter. - Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry. * [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: Eric Eastwood <erice@element.io>
This commit is contained in:
@@ -212,6 +212,66 @@ class JsonResourceTests(unittest.TestCase):
|
||||
self.assertEqual(channel.code, 200)
|
||||
self.assertNotIn("body", channel.result)
|
||||
|
||||
def test_content_larger_than_content_length(self) -> None:
|
||||
"""
|
||||
HTTP requests with content size exceeding Content-Length should be rejected with 400.
|
||||
"""
|
||||
|
||||
def _callback(
|
||||
request: SynapseRequest, **kwargs: object
|
||||
) -> tuple[int, JsonDict]:
|
||||
return 200, {}
|
||||
|
||||
res = JsonResource(self.homeserver)
|
||||
res.register_paths(
|
||||
"POST", [re.compile("^/_matrix/foo$")], _callback, "test_servlet"
|
||||
)
|
||||
|
||||
channel = make_request(
|
||||
self.reactor,
|
||||
FakeSite(res, self.reactor),
|
||||
b"POST",
|
||||
b"/_matrix/foo",
|
||||
{},
|
||||
# Set the `Content-Length` value to be smaller than the actual content size
|
||||
custom_headers=[("Content-Length", "1")],
|
||||
# The request should disconnect early so don't await the result
|
||||
await_result=False,
|
||||
)
|
||||
|
||||
self.reactor.advance(0.1)
|
||||
self.assertEqual(channel.code, 400)
|
||||
|
||||
def test_content_smaller_than_content_length(self) -> None:
|
||||
"""
|
||||
HTTP requests with content size smaller than Content-Length should be rejected with 400.
|
||||
"""
|
||||
|
||||
def _callback(
|
||||
request: SynapseRequest, **kwargs: object
|
||||
) -> tuple[int, JsonDict]:
|
||||
return 200, {}
|
||||
|
||||
res = JsonResource(self.homeserver)
|
||||
res.register_paths(
|
||||
"POST", [re.compile("^/_matrix/foo$")], _callback, "test_servlet"
|
||||
)
|
||||
|
||||
channel = make_request(
|
||||
self.reactor,
|
||||
FakeSite(res, self.reactor),
|
||||
b"POST",
|
||||
b"/_matrix/foo",
|
||||
{},
|
||||
# Set the `Content-Length` value to be larger than the actual content size
|
||||
custom_headers=[("Content-Length", "10")],
|
||||
# The request should disconnect early so don't await the result
|
||||
await_result=False,
|
||||
)
|
||||
|
||||
self.reactor.advance(0.1)
|
||||
self.assertEqual(channel.code, 400)
|
||||
|
||||
|
||||
class OptionsResourceTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user