forked from MirrorHub/synapse
Fix media repo breaking (#5593)
This commit is contained in:
parent
f8b52eb8c5
commit
0ee9076ffe
6 changed files with 60 additions and 26 deletions
1
changelog.d/5593.bugfix
Normal file
1
changelog.d/5593.bugfix
Normal file
|
@ -0,0 +1 @@
|
|||
Fix regression in 1.1rc1 where OPTIONS requests to the media repo would fail.
|
|
@ -65,8 +65,8 @@ def wrap_json_request_handler(h):
|
|||
The handler method must have a signature of "handle_foo(self, request)",
|
||||
where "request" must be a SynapseRequest.
|
||||
|
||||
The handler must return a deferred. If the deferred succeeds we assume that
|
||||
a response has been sent. If the deferred fails with a SynapseError we use
|
||||
The handler must return a deferred or a coroutine. If the deferred succeeds
|
||||
we assume that a response has been sent. If the deferred fails with a SynapseError we use
|
||||
it to send a JSON response with the appropriate HTTP reponse code. If the
|
||||
deferred fails with any other type of error we send a 500 reponse.
|
||||
"""
|
||||
|
@ -353,16 +353,22 @@ class DirectServeResource(resource.Resource):
|
|||
"""
|
||||
Render the request, using an asynchronous render handler if it exists.
|
||||
"""
|
||||
render_callback_name = "_async_render_" + request.method.decode("ascii")
|
||||
async_render_callback_name = "_async_render_" + request.method.decode("ascii")
|
||||
|
||||
if hasattr(self, render_callback_name):
|
||||
# Call the handler
|
||||
callback = getattr(self, render_callback_name)
|
||||
defer.ensureDeferred(callback(request))
|
||||
# Try and get the async renderer
|
||||
callback = getattr(self, async_render_callback_name, None)
|
||||
|
||||
return NOT_DONE_YET
|
||||
else:
|
||||
super().render(request)
|
||||
# No async renderer for this request method.
|
||||
if not callback:
|
||||
return super().render(request)
|
||||
|
||||
resp = callback(request)
|
||||
|
||||
# If it's a coroutine, turn it into a Deferred
|
||||
if isinstance(resp, types.CoroutineType):
|
||||
defer.ensureDeferred(resp)
|
||||
|
||||
return NOT_DONE_YET
|
||||
|
||||
|
||||
def _options_handler(request):
|
||||
|
|
|
@ -95,6 +95,7 @@ class PreviewUrlResource(DirectServeResource):
|
|||
)
|
||||
|
||||
def render_OPTIONS(self, request):
|
||||
request.setHeader(b"Allow", b"OPTIONS, GET")
|
||||
return respond_with_json(request, 200, {}, send_cors=True)
|
||||
|
||||
@wrap_json_request_handler
|
||||
|
|
|
@ -24,6 +24,7 @@ See doc/log_contexts.rst for details on how this works.
|
|||
|
||||
import logging
|
||||
import threading
|
||||
import types
|
||||
|
||||
from twisted.internet import defer, threads
|
||||
|
||||
|
@ -528,8 +529,9 @@ def run_in_background(f, *args, **kwargs):
|
|||
return from the function, and that the sentinel context is set once the
|
||||
deferred returned by the function completes.
|
||||
|
||||
Useful for wrapping functions that return a deferred which you don't yield
|
||||
on (for instance because you want to pass it to deferred.gatherResults()).
|
||||
Useful for wrapping functions that return a deferred or coroutine, which you don't
|
||||
yield or await on (for instance because you want to pass it to
|
||||
deferred.gatherResults()).
|
||||
|
||||
Note that if you completely discard the result, you should make sure that
|
||||
`f` doesn't raise any deferred exceptions, otherwise a scary-looking
|
||||
|
@ -544,6 +546,9 @@ def run_in_background(f, *args, **kwargs):
|
|||
# by synchronous exceptions, so let's turn them into Failures.
|
||||
return defer.fail()
|
||||
|
||||
if isinstance(res, types.CoroutineType):
|
||||
res = defer.ensureDeferred(res)
|
||||
|
||||
if not isinstance(res, defer.Deferred):
|
||||
return res
|
||||
|
||||
|
|
|
@ -460,3 +460,15 @@ class URLPreviewTests(unittest.HomeserverTestCase):
|
|||
"error": "DNS resolution failure during URL preview generation",
|
||||
},
|
||||
)
|
||||
|
||||
def test_OPTIONS(self):
|
||||
"""
|
||||
OPTIONS returns the OPTIONS.
|
||||
"""
|
||||
request, channel = self.make_request(
|
||||
"OPTIONS", "url_preview?url=http://example.com", shorthand=False
|
||||
)
|
||||
request.render(self.preview_url)
|
||||
self.pump()
|
||||
self.assertEqual(channel.code, 200)
|
||||
self.assertEqual(channel.json_body, {})
|
||||
|
|
|
@ -39,24 +39,17 @@ class LoggingContextTestCase(unittest.TestCase):
|
|||
|
||||
callback_completed = [False]
|
||||
|
||||
def test():
|
||||
context_one.request = "one"
|
||||
d = function()
|
||||
|
||||
def cb(res):
|
||||
self._check_test_key("one")
|
||||
callback_completed[0] = True
|
||||
return res
|
||||
|
||||
d.addCallback(cb)
|
||||
|
||||
return d
|
||||
|
||||
with LoggingContext() as context_one:
|
||||
context_one.request = "one"
|
||||
|
||||
# fire off function, but don't wait on it.
|
||||
logcontext.run_in_background(test)
|
||||
d2 = logcontext.run_in_background(function)
|
||||
|
||||
def cb(res):
|
||||
callback_completed[0] = True
|
||||
return res
|
||||
|
||||
d2.addCallback(cb)
|
||||
|
||||
self._check_test_key("one")
|
||||
|
||||
|
@ -105,6 +98,22 @@ class LoggingContextTestCase(unittest.TestCase):
|
|||
|
||||
return self._test_run_in_background(testfunc)
|
||||
|
||||
def test_run_in_background_with_coroutine(self):
|
||||
async def testfunc():
|
||||
self._check_test_key("one")
|
||||
d = Clock(reactor).sleep(0)
|
||||
self.assertIs(LoggingContext.current_context(), LoggingContext.sentinel)
|
||||
await d
|
||||
self._check_test_key("one")
|
||||
|
||||
return self._test_run_in_background(testfunc)
|
||||
|
||||
def test_run_in_background_with_nonblocking_coroutine(self):
|
||||
async def testfunc():
|
||||
self._check_test_key("one")
|
||||
|
||||
return self._test_run_in_background(testfunc)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def test_make_deferred_yieldable(self):
|
||||
# a function which retuns an incomplete deferred, but doesn't follow
|
||||
|
|
Loading…
Reference in a new issue