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

Commit 0ee9076

Browse files
hawkowlrichvdh
authored andcommitted
Fix media repo breaking (#5593)
1 parent f8b52eb commit 0ee9076

File tree

6 files changed

+58
-24
lines changed

6 files changed

+58
-24
lines changed

changelog.d/5593.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix regression in 1.1rc1 where OPTIONS requests to the media repo would fail.

synapse/http/server.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ def wrap_json_request_handler(h):
6565
The handler method must have a signature of "handle_foo(self, request)",
6666
where "request" must be a SynapseRequest.
6767
68-
The handler must return a deferred. If the deferred succeeds we assume that
69-
a response has been sent. If the deferred fails with a SynapseError we use
68+
The handler must return a deferred or a coroutine. If the deferred succeeds
69+
we assume that a response has been sent. If the deferred fails with a SynapseError we use
7070
it to send a JSON response with the appropriate HTTP reponse code. If the
7171
deferred fails with any other type of error we send a 500 reponse.
7272
"""
@@ -353,16 +353,22 @@ def render(self, request):
353353
"""
354354
Render the request, using an asynchronous render handler if it exists.
355355
"""
356-
render_callback_name = "_async_render_" + request.method.decode("ascii")
356+
async_render_callback_name = "_async_render_" + request.method.decode("ascii")
357357

358-
if hasattr(self, render_callback_name):
359-
# Call the handler
360-
callback = getattr(self, render_callback_name)
361-
defer.ensureDeferred(callback(request))
358+
# Try and get the async renderer
359+
callback = getattr(self, async_render_callback_name, None)
362360

363-
return NOT_DONE_YET
364-
else:
365-
super().render(request)
361+
# No async renderer for this request method.
362+
if not callback:
363+
return super().render(request)
364+
365+
resp = callback(request)
366+
367+
# If it's a coroutine, turn it into a Deferred
368+
if isinstance(resp, types.CoroutineType):
369+
defer.ensureDeferred(resp)
370+
371+
return NOT_DONE_YET
366372

367373

368374
def _options_handler(request):

synapse/rest/media/v1/preview_url_resource.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ def __init__(self, hs, media_repo, media_storage):
9595
)
9696

9797
def render_OPTIONS(self, request):
98+
request.setHeader(b"Allow", b"OPTIONS, GET")
9899
return respond_with_json(request, 200, {}, send_cors=True)
99100

100101
@wrap_json_request_handler

synapse/util/logcontext.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import logging
2626
import threading
27+
import types
2728

2829
from twisted.internet import defer, threads
2930

@@ -528,8 +529,9 @@ def run_in_background(f, *args, **kwargs):
528529
return from the function, and that the sentinel context is set once the
529530
deferred returned by the function completes.
530531
531-
Useful for wrapping functions that return a deferred which you don't yield
532-
on (for instance because you want to pass it to deferred.gatherResults()).
532+
Useful for wrapping functions that return a deferred or coroutine, which you don't
533+
yield or await on (for instance because you want to pass it to
534+
deferred.gatherResults()).
533535
534536
Note that if you completely discard the result, you should make sure that
535537
`f` doesn't raise any deferred exceptions, otherwise a scary-looking
@@ -544,6 +546,9 @@ def run_in_background(f, *args, **kwargs):
544546
# by synchronous exceptions, so let's turn them into Failures.
545547
return defer.fail()
546548

549+
if isinstance(res, types.CoroutineType):
550+
res = defer.ensureDeferred(res)
551+
547552
if not isinstance(res, defer.Deferred):
548553
return res
549554

tests/rest/media/v1/test_url_preview.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,15 @@ def test_blacklisted_ipv6_range(self):
460460
"error": "DNS resolution failure during URL preview generation",
461461
},
462462
)
463+
464+
def test_OPTIONS(self):
465+
"""
466+
OPTIONS returns the OPTIONS.
467+
"""
468+
request, channel = self.make_request(
469+
"OPTIONS", "url_preview?url=http://example.com", shorthand=False
470+
)
471+
request.render(self.preview_url)
472+
self.pump()
473+
self.assertEqual(channel.code, 200)
474+
self.assertEqual(channel.json_body, {})

tests/util/test_logcontext.py

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,17 @@ def _test_run_in_background(self, function):
3939

4040
callback_completed = [False]
4141

42-
def test():
42+
with LoggingContext() as context_one:
4343
context_one.request = "one"
44-
d = function()
44+
45+
# fire off function, but don't wait on it.
46+
d2 = logcontext.run_in_background(function)
4547

4648
def cb(res):
47-
self._check_test_key("one")
4849
callback_completed[0] = True
4950
return res
5051

51-
d.addCallback(cb)
52-
53-
return d
54-
55-
with LoggingContext() as context_one:
56-
context_one.request = "one"
57-
58-
# fire off function, but don't wait on it.
59-
logcontext.run_in_background(test)
52+
d2.addCallback(cb)
6053

6154
self._check_test_key("one")
6255

@@ -105,6 +98,22 @@ def testfunc():
10598

10699
return self._test_run_in_background(testfunc)
107100

101+
def test_run_in_background_with_coroutine(self):
102+
async def testfunc():
103+
self._check_test_key("one")
104+
d = Clock(reactor).sleep(0)
105+
self.assertIs(LoggingContext.current_context(), LoggingContext.sentinel)
106+
await d
107+
self._check_test_key("one")
108+
109+
return self._test_run_in_background(testfunc)
110+
111+
def test_run_in_background_with_nonblocking_coroutine(self):
112+
async def testfunc():
113+
self._check_test_key("one")
114+
115+
return self._test_run_in_background(testfunc)
116+
108117
@defer.inlineCallbacks
109118
def test_make_deferred_yieldable(self):
110119
# a function which retuns an incomplete deferred, but doesn't follow

0 commit comments

Comments
 (0)