Fix media repo breaking (#5593)

code_spécifique_watcha
Amber Brown 5 years ago committed by Richard van der Hoff
parent f8b52eb8c5
commit 0ee9076ffe
  1. 1
      changelog.d/5593.bugfix
  2. 26
      synapse/http/server.py
  3. 1
      synapse/rest/media/v1/preview_url_resource.py
  4. 9
      synapse/util/logcontext.py
  5. 12
      tests/rest/media/v1/test_url_preview.py
  6. 33
      tests/util/test_logcontext.py

@ -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)", The handler method must have a signature of "handle_foo(self, request)",
where "request" must be a SynapseRequest. where "request" must be a SynapseRequest.
The handler must return a deferred. If the deferred succeeds we assume that The handler must return a deferred or a coroutine. If the deferred succeeds
a response has been sent. If the deferred fails with a SynapseError we use 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 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. 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 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): # Try and get the async renderer
# Call the handler callback = getattr(self, async_render_callback_name, None)
callback = getattr(self, render_callback_name)
defer.ensureDeferred(callback(request))
return NOT_DONE_YET # No async renderer for this request method.
else: if not callback:
super().render(request) 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): def _options_handler(request):

@ -95,6 +95,7 @@ class PreviewUrlResource(DirectServeResource):
) )
def render_OPTIONS(self, request): def render_OPTIONS(self, request):
request.setHeader(b"Allow", b"OPTIONS, GET")
return respond_with_json(request, 200, {}, send_cors=True) return respond_with_json(request, 200, {}, send_cors=True)
@wrap_json_request_handler @wrap_json_request_handler

@ -24,6 +24,7 @@ See doc/log_contexts.rst for details on how this works.
import logging import logging
import threading import threading
import types
from twisted.internet import defer, threads 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 return from the function, and that the sentinel context is set once the
deferred returned by the function completes. deferred returned by the function completes.
Useful for wrapping functions that return a deferred which you don't yield Useful for wrapping functions that return a deferred or coroutine, which you don't
on (for instance because you want to pass it to deferred.gatherResults()). 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 Note that if you completely discard the result, you should make sure that
`f` doesn't raise any deferred exceptions, otherwise a scary-looking `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. # by synchronous exceptions, so let's turn them into Failures.
return defer.fail() return defer.fail()
if isinstance(res, types.CoroutineType):
res = defer.ensureDeferred(res)
if not isinstance(res, defer.Deferred): if not isinstance(res, defer.Deferred):
return res return res

@ -460,3 +460,15 @@ class URLPreviewTests(unittest.HomeserverTestCase):
"error": "DNS resolution failure during URL preview generation", "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] callback_completed = [False]
def test(): with LoggingContext() as context_one:
context_one.request = "one" context_one.request = "one"
d = function()
# fire off function, but don't wait on it.
d2 = logcontext.run_in_background(function)
def cb(res): def cb(res):
self._check_test_key("one")
callback_completed[0] = True callback_completed[0] = True
return res return res
d.addCallback(cb) d2.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)
self._check_test_key("one") self._check_test_key("one")
@ -105,6 +98,22 @@ class LoggingContextTestCase(unittest.TestCase):
return self._test_run_in_background(testfunc) 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 @defer.inlineCallbacks
def test_make_deferred_yieldable(self): def test_make_deferred_yieldable(self):
# a function which retuns an incomplete deferred, but doesn't follow # a function which retuns an incomplete deferred, but doesn't follow

Loading…
Cancel
Save