2018-09-20 00:28:18 -06:00
#
2023-11-21 13:29:58 -07:00
# This file is licensed under the Affero General Public License (AGPL) version 3.
#
# Copyright (C) 2023 New Vector, Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# See the GNU Affero General Public License for more details:
# <https://www.gnu.org/licenses/agpl-3.0.html>.
#
# Originally licensed under the Apache License, Version 2.0:
# <http://www.apache.org/licenses/LICENSE-2.0>.
#
# [This file includes modifications made by New Vector Limited]
2018-09-20 00:28:18 -06:00
#
#
2018-06-27 03:37:24 -06:00
import re
2022-05-11 05:24:48 -06:00
from http import HTTPStatus
2022-06-28 06:12:17 -06:00
from typing import Awaitable , Callable , Dict , NoReturn , Optional , Tuple
2018-09-20 00:28:18 -06:00
2018-06-27 03:37:24 -06:00
from twisted . internet . defer import Deferred
2018-09-20 00:28:18 -06:00
from twisted . web . resource import Resource
2018-06-27 03:37:24 -06:00
2020-01-15 08:58:55 -07:00
from synapse . api . errors import Codes , RedirectException , SynapseError
2020-06-16 05:44:07 -06:00
from synapse . config . server import parse_listener_def
2022-05-11 05:24:48 -06:00
from synapse . http . server import (
DirectServeHtmlResource ,
DirectServeJsonResource ,
JsonResource ,
OptionsResource ,
)
from synapse . http . site import SynapseRequest , SynapseSite
2019-07-03 08:07:04 -06:00
from synapse . logging . context import make_deferred_yieldable
2022-05-11 05:24:48 -06:00
from synapse . types import JsonDict
2018-07-09 00:09:20 -06:00
from synapse . util import Clock
2022-08-31 05:16:05 -06:00
from synapse . util . cancellation import cancellable
2018-07-09 00:09:20 -06:00
2018-06-27 03:37:24 -06:00
from tests import unittest
2022-06-07 11:17:32 -06:00
from tests . http . server . _base import test_disconnect
2019-01-24 03:31:54 -07:00
from tests . server import (
2022-06-28 06:12:17 -06:00
FakeChannel ,
2020-11-13 15:39:09 -07:00
FakeSite ,
2023-07-18 02:49:21 -06:00
get_clock ,
2019-01-24 03:31:54 -07:00
make_request ,
setup_test_homeserver ,
)
2018-06-27 03:37:24 -06:00
class JsonResourceTests ( unittest . TestCase ) :
2022-06-28 06:12:17 -06:00
def setUp ( self ) - > None :
2023-07-18 02:49:21 -06:00
reactor , clock = get_clock ( )
self . reactor = reactor
2018-06-27 03:37:24 -06:00
self . homeserver = setup_test_homeserver (
2020-12-02 09:09:24 -07:00
self . addCleanup ,
2023-07-18 02:49:21 -06:00
clock = clock ,
2020-12-02 09:09:24 -07:00
reactor = self . reactor ,
2018-06-27 03:37:24 -06:00
)
2022-06-28 06:12:17 -06:00
def test_handler_for_request ( self ) - > None :
2018-06-27 03:37:24 -06:00
"""
JsonResource . handler_for_request gives correctly decoded URL args to
the callback , while Twisted will give the raw bytes of URL query
arguments .
"""
got_kwargs = { }
2022-06-28 06:12:17 -06:00
def _callback (
request : SynapseRequest , * * kwargs : object
) - > Tuple [ int , Dict [ str , object ] ] :
2018-06-27 03:37:24 -06:00
got_kwargs . update ( kwargs )
2019-08-30 09:28:26 -06:00
return 200 , kwargs
2018-06-27 03:37:24 -06:00
res = JsonResource ( self . homeserver )
2018-07-17 04:43:18 -06:00
res . register_paths (
2019-07-24 06:07:35 -06:00
" GET " ,
[ re . compile ( " ^/_matrix/foo/(?P<room_id>[^/]*)$ " ) ] ,
_callback ,
" test_servlet " ,
2018-07-17 04:43:18 -06:00
)
2018-06-27 03:37:24 -06:00
2020-12-15 07:54:41 -07:00
make_request (
2021-09-24 04:01:25 -06:00
self . reactor ,
FakeSite ( res , self . reactor ) ,
b " GET " ,
b " /_matrix/foo/ %E 2 %98% 83?a= %E 2 %98% 83 " ,
2018-11-06 09:00:00 -07:00
)
2018-06-27 03:37:24 -06:00
self . assertEqual ( got_kwargs , { " room_id " : " \N{SNOWMAN} " } )
2022-06-28 06:12:17 -06:00
def test_callback_direct_exception ( self ) - > None :
2018-06-27 03:37:24 -06:00
"""
If the web callback raises an uncaught exception , it will be translated
into a 500.
"""
2022-06-28 06:12:17 -06:00
def _callback ( request : SynapseRequest , * * kwargs : object ) - > NoReturn :
2018-06-27 03:37:24 -06:00
raise Exception ( " boo " )
res = JsonResource ( self . homeserver )
2019-07-24 06:07:35 -06:00
res . register_paths (
" GET " , [ re . compile ( " ^/_matrix/foo$ " ) ] , _callback , " test_servlet "
)
2018-06-27 03:37:24 -06:00
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /_matrix/foo "
)
2018-06-27 03:37:24 -06:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 500 )
2018-06-27 03:37:24 -06:00
2022-06-28 06:12:17 -06:00
def test_callback_indirect_exception ( self ) - > None :
2018-06-27 03:37:24 -06:00
"""
If the web callback raises an uncaught exception in a Deferred , it will
be translated into a 500.
"""
2022-06-28 06:12:17 -06:00
def _throw ( * args : object ) - > NoReturn :
2018-06-27 03:37:24 -06:00
raise Exception ( " boo " )
2022-06-28 06:12:17 -06:00
def _callback ( request : SynapseRequest , * * kwargs : object ) - > " Deferred[None] " :
d : " Deferred[None] " = Deferred ( )
2018-06-27 03:37:24 -06:00
d . addCallback ( _throw )
2021-09-24 04:01:25 -06:00
self . reactor . callLater ( 0.5 , d . callback , True )
2018-11-15 15:46:51 -07:00
return make_deferred_yieldable ( d )
2018-06-27 03:37:24 -06:00
res = JsonResource ( self . homeserver )
2019-07-24 06:07:35 -06:00
res . register_paths (
" GET " , [ re . compile ( " ^/_matrix/foo$ " ) ] , _callback , " test_servlet "
)
2018-06-27 03:37:24 -06:00
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /_matrix/foo "
)
2018-06-27 03:37:24 -06:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 500 )
2018-06-27 03:37:24 -06:00
2022-06-28 06:12:17 -06:00
def test_callback_synapseerror ( self ) - > None :
2018-06-27 03:37:24 -06:00
"""
If the web callback raises a SynapseError , it returns the appropriate
status code and message set in it .
"""
2022-06-28 06:12:17 -06:00
def _callback ( request : SynapseRequest , * * kwargs : object ) - > NoReturn :
2018-06-27 03:37:24 -06:00
raise SynapseError ( 403 , " Forbidden!!one! " , Codes . FORBIDDEN )
res = JsonResource ( self . homeserver )
2019-07-24 06:07:35 -06:00
res . register_paths (
" GET " , [ re . compile ( " ^/_matrix/foo$ " ) ] , _callback , " test_servlet "
)
2018-06-27 03:37:24 -06:00
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /_matrix/foo "
)
2018-06-27 03:37:24 -06:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 403 )
2018-08-08 20:22:01 -06:00
self . assertEqual ( channel . json_body [ " error " ] , " Forbidden!!one! " )
self . assertEqual ( channel . json_body [ " errcode " ] , " M_FORBIDDEN " )
2018-06-27 03:37:24 -06:00
2022-06-28 06:12:17 -06:00
def test_no_handler ( self ) - > None :
2018-06-27 03:37:24 -06:00
"""
If there is no handler to process the request , Synapse will return 400.
"""
2022-06-28 06:12:17 -06:00
def _callback ( request : SynapseRequest , * * kwargs : object ) - > None :
2018-06-27 03:37:24 -06:00
"""
Not ever actually called !
"""
self . fail ( " shouldn ' t ever get here " )
res = JsonResource ( self . homeserver )
2019-07-24 06:07:35 -06:00
res . register_paths (
" GET " , [ re . compile ( " ^/_matrix/foo$ " ) ] , _callback , " test_servlet "
)
2018-06-27 03:37:24 -06:00
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /_matrix/foobar "
)
2018-06-27 03:37:24 -06:00
2022-12-08 09:37:05 -07:00
self . assertEqual ( channel . code , 404 )
2018-08-08 20:22:01 -06:00
self . assertEqual ( channel . json_body [ " error " ] , " Unrecognized request " )
self . assertEqual ( channel . json_body [ " errcode " ] , " M_UNRECOGNIZED " )
2018-09-20 00:28:18 -06:00
2022-06-28 06:12:17 -06:00
def test_head_request ( self ) - > None :
2020-08-03 06:45:42 -06:00
"""
JsonResource . handler_for_request gives correctly decoded URL args to
the callback , while Twisted will give the raw bytes of URL query
arguments .
"""
2022-06-28 06:12:17 -06:00
def _callback (
request : SynapseRequest , * * kwargs : object
) - > Tuple [ int , Dict [ str , object ] ] :
2020-08-03 06:45:42 -06:00
return 200 , { " result " : True }
res = JsonResource ( self . homeserver )
res . register_paths (
" GET " ,
[ re . compile ( " ^/_matrix/foo$ " ) ] ,
_callback ,
" test_servlet " ,
)
# The path was registered as GET, but this is a HEAD request.
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " HEAD " , b " /_matrix/foo "
)
2020-08-03 06:45:42 -06:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 200 )
2020-08-03 06:45:42 -06:00
self . assertNotIn ( " body " , channel . result )
2018-09-20 00:28:18 -06:00
2020-05-22 07:30:07 -06:00
class OptionsResourceTests ( unittest . TestCase ) :
2022-06-28 06:12:17 -06:00
def setUp ( self ) - > None :
2023-07-18 02:49:21 -06:00
reactor , clock = get_clock ( )
self . reactor = reactor
self . homeserver = setup_test_homeserver (
self . addCleanup ,
clock = clock ,
reactor = self . reactor ,
)
2020-05-22 07:30:07 -06:00
class DummyResource ( Resource ) :
isLeaf = True
2022-06-28 06:12:17 -06:00
def render ( self , request : SynapseRequest ) - > bytes :
# Type-ignore: mypy thinks request.path is Optional[Any], not bytes.
return request . path # type: ignore[return-value]
2020-05-22 07:30:07 -06:00
# Setup a resource with some children.
self . resource = OptionsResource ( )
self . resource . putChild ( b " res " , DummyResource ( ) )
2022-10-18 09:52:25 -06:00
def _make_request (
self , method : bytes , path : bytes , experimental_cors_msc3886 : bool = False
) - > FakeChannel :
2020-05-22 07:30:07 -06:00
""" Create a request from the method/path and return a channel with the response. """
# Create a site and query for the resource.
2020-06-16 05:44:07 -06:00
site = SynapseSite (
" test " ,
" site_tag " ,
2022-10-18 09:52:25 -06:00
parse_listener_def (
0 ,
{
" type " : " http " ,
" port " : 0 ,
" experimental_cors_msc3886 " : experimental_cors_msc3886 ,
} ,
) ,
2020-06-16 05:44:07 -06:00
self . resource ,
" 1.0 " ,
2022-07-19 05:45:17 -06:00
max_request_body_size = 4096 ,
2021-04-23 10:06:47 -06:00
reactor = self . reactor ,
2023-07-18 02:49:21 -06:00
hs = self . homeserver ,
2020-06-16 05:44:07 -06:00
)
2020-11-13 15:39:09 -07:00
2020-11-15 15:49:21 -07:00
# render the request and return the channel
2020-12-15 07:44:04 -07:00
channel = make_request ( self . reactor , site , method , path , shorthand = False )
2020-05-22 07:30:07 -06:00
return channel
2022-10-18 09:52:25 -06:00
def _check_cors_standard_headers ( self , channel : FakeChannel ) - > None :
# Ensure the correct CORS headers have been added
# as per https://spec.matrix.org/v1.4/client-server-api/#web-browser-clients
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Allow-Origin " ) ,
[ b " * " ] ,
" has correct CORS Origin header " ,
)
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Allow-Methods " ) ,
[ b " GET, HEAD, POST, PUT, DELETE, OPTIONS " ] , # HEAD isn't in the spec
" has correct CORS Methods header " ,
)
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Allow-Headers " ) ,
[ b " X-Requested-With, Content-Type, Authorization, Date " ] ,
" has correct CORS Headers header " ,
)
2023-03-20 12:14:05 -06:00
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Expose-Headers " ) ,
2023-07-11 02:18:50 -06:00
[ b " Synapse-Trace-Id, Server " ] ,
2023-03-20 12:14:05 -06:00
)
2022-10-18 09:52:25 -06:00
def _check_cors_msc3886_headers ( self , channel : FakeChannel ) - > None :
# Ensure the correct CORS headers have been added
# as per https://github.com/matrix-org/matrix-spec-proposals/blob/hughns/simple-rendezvous-capability/proposals/3886-simple-rendezvous-capability.md#cors
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Allow-Origin " ) ,
[ b " * " ] ,
" has correct CORS Origin header " ,
)
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Allow-Methods " ) ,
[ b " GET, HEAD, POST, PUT, DELETE, OPTIONS " ] , # HEAD isn't in the spec
" has correct CORS Methods header " ,
)
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Allow-Headers " ) ,
[
b " X-Requested-With, Content-Type, Authorization, Date, If-Match, If-None-Match "
] ,
" has correct CORS Headers header " ,
)
self . assertEqual (
channel . headers . getRawHeaders ( b " Access-Control-Expose-Headers " ) ,
[ b " ETag, Location, X-Max-Bytes " ] ,
" has correct CORS Expose Headers header " ,
)
2022-06-28 06:12:17 -06:00
def test_unknown_options_request ( self ) - > None :
2020-07-24 05:08:07 -06:00
""" An OPTIONS requests to an unknown URL still returns 204 No Content. """
2020-05-22 07:30:07 -06:00
channel = self . _make_request ( b " OPTIONS " , b " /foo/ " )
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 204 )
2020-07-24 05:08:07 -06:00
self . assertNotIn ( " body " , channel . result )
2020-05-22 07:30:07 -06:00
2022-10-18 09:52:25 -06:00
self . _check_cors_standard_headers ( channel )
2020-05-22 10:42:39 -06:00
2022-06-28 06:12:17 -06:00
def test_known_options_request ( self ) - > None :
2020-07-24 05:08:07 -06:00
""" An OPTIONS requests to an known URL still returns 204 No Content. """
2020-05-22 07:30:07 -06:00
channel = self . _make_request ( b " OPTIONS " , b " /res/ " )
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 204 )
2020-07-24 05:08:07 -06:00
self . assertNotIn ( " body " , channel . result )
2020-05-22 07:30:07 -06:00
2022-10-18 09:52:25 -06:00
self . _check_cors_standard_headers ( channel )
def test_known_options_request_msc3886 ( self ) - > None :
""" An OPTIONS requests to an known URL still returns 204 No Content. """
channel = self . _make_request (
b " OPTIONS " , b " /res/ " , experimental_cors_msc3886 = True
2020-05-22 10:42:39 -06:00
)
2022-10-18 09:52:25 -06:00
self . assertEqual ( channel . code , 204 )
self . assertNotIn ( " body " , channel . result )
self . _check_cors_msc3886_headers ( channel )
2020-05-22 10:42:39 -06:00
2022-06-28 06:12:17 -06:00
def test_unknown_request ( self ) - > None :
2020-05-22 07:30:07 -06:00
""" A non-OPTIONS request to an unknown URL should 404. """
channel = self . _make_request ( b " GET " , b " /foo/ " )
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 404 )
2020-05-22 07:30:07 -06:00
2022-06-28 06:12:17 -06:00
def test_known_request ( self ) - > None :
2020-05-22 07:30:07 -06:00
""" A non-OPTIONS request to an known URL should query the proper resource. """
channel = self . _make_request ( b " GET " , b " /res/ " )
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 200 )
2020-05-22 07:30:07 -06:00
self . assertEqual ( channel . result [ " body " ] , b " /res/ " )
2020-01-15 08:58:55 -07:00
class WrapHtmlRequestHandlerTests ( unittest . TestCase ) :
2020-07-03 12:02:19 -06:00
class TestResource ( DirectServeHtmlResource ) :
2022-06-28 06:12:17 -06:00
callback : Optional [ Callable [ . . . , Awaitable [ None ] ] ]
2020-01-15 08:58:55 -07:00
2022-06-28 06:12:17 -06:00
async def _async_render_GET ( self , request : SynapseRequest ) - > None :
assert self . callback is not None
2020-07-03 12:02:19 -06:00
await self . callback ( request )
2020-01-15 08:58:55 -07:00
2022-06-28 06:12:17 -06:00
def setUp ( self ) - > None :
2023-07-18 02:49:21 -06:00
reactor , _ = get_clock ( )
self . reactor = reactor
2020-01-15 08:58:55 -07:00
2022-06-28 06:12:17 -06:00
def test_good_response ( self ) - > None :
async def callback ( request : SynapseRequest ) - > None :
2020-01-15 08:58:55 -07:00
request . write ( b " response " )
request . finish ( )
res = WrapHtmlRequestHandlerTests . TestResource ( )
res . callback = callback
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /path "
)
2020-01-15 08:58:55 -07:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 200 )
2020-01-15 08:58:55 -07:00
body = channel . result [ " body " ]
self . assertEqual ( body , b " response " )
2022-06-28 06:12:17 -06:00
def test_redirect_exception ( self ) - > None :
2020-01-15 08:58:55 -07:00
"""
If the callback raises a RedirectException , it is turned into a 30 x
with the right location .
"""
2022-06-28 06:12:17 -06:00
async def callback ( request : SynapseRequest , * * kwargs : object ) - > None :
2020-01-15 08:58:55 -07:00
raise RedirectException ( b " /look/an/eagle " , 301 )
res = WrapHtmlRequestHandlerTests . TestResource ( )
res . callback = callback
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /path "
)
2020-01-15 08:58:55 -07:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 301 )
2020-01-15 08:58:55 -07:00
headers = channel . result [ " headers " ]
location_headers = [ v for k , v in headers if k == b " Location " ]
self . assertEqual ( location_headers , [ b " /look/an/eagle " ] )
2022-06-28 06:12:17 -06:00
def test_redirect_exception_with_cookie ( self ) - > None :
2020-01-15 08:58:55 -07:00
"""
If the callback raises a RedirectException which sets a cookie , that is
returned too
"""
2022-06-28 06:12:17 -06:00
async def callback ( request : SynapseRequest , * * kwargs : object ) - > NoReturn :
2020-01-15 08:58:55 -07:00
e = RedirectException ( b " /no/over/there " , 304 )
e . cookies . append ( b " session=yespls " )
raise e
res = WrapHtmlRequestHandlerTests . TestResource ( )
res . callback = callback
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " GET " , b " /path "
)
2020-01-15 08:58:55 -07:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 304 )
2020-01-15 08:58:55 -07:00
headers = channel . result [ " headers " ]
location_headers = [ v for k , v in headers if k == b " Location " ]
self . assertEqual ( location_headers , [ b " /no/over/there " ] )
cookies_headers = [ v for k , v in headers if k == b " Set-Cookie " ]
self . assertEqual ( cookies_headers , [ b " session=yespls " ] )
2020-08-03 06:45:42 -06:00
2022-06-28 06:12:17 -06:00
def test_head_request ( self ) - > None :
2020-08-03 06:45:42 -06:00
""" A head request should work by being turned into a GET request. """
2022-06-28 06:12:17 -06:00
async def callback ( request : SynapseRequest ) - > None :
2020-08-03 06:45:42 -06:00
request . write ( b " response " )
request . finish ( )
res = WrapHtmlRequestHandlerTests . TestResource ( )
res . callback = callback
2021-09-24 04:01:25 -06:00
channel = make_request (
self . reactor , FakeSite ( res , self . reactor ) , b " HEAD " , b " /path "
)
2020-08-03 06:45:42 -06:00
2022-08-05 08:59:09 -06:00
self . assertEqual ( channel . code , 200 )
2020-08-03 06:45:42 -06:00
self . assertNotIn ( " body " , channel . result )
2022-05-11 05:24:48 -06:00
class CancellableDirectServeJsonResource ( DirectServeJsonResource ) :
def __init__ ( self , clock : Clock ) :
super ( ) . __init__ ( )
self . clock = clock
@cancellable
async def _async_render_GET ( self , request : SynapseRequest ) - > Tuple [ int , JsonDict ] :
await self . clock . sleep ( 1.0 )
return HTTPStatus . OK , { " result " : True }
async def _async_render_POST ( self , request : SynapseRequest ) - > Tuple [ int , JsonDict ] :
await self . clock . sleep ( 1.0 )
return HTTPStatus . OK , { " result " : True }
class CancellableDirectServeHtmlResource ( DirectServeHtmlResource ) :
ERROR_TEMPLATE = " {code} {msg} "
def __init__ ( self , clock : Clock ) :
super ( ) . __init__ ( )
self . clock = clock
@cancellable
async def _async_render_GET ( self , request : SynapseRequest ) - > Tuple [ int , bytes ] :
await self . clock . sleep ( 1.0 )
return HTTPStatus . OK , b " ok "
async def _async_render_POST ( self , request : SynapseRequest ) - > Tuple [ int , bytes ] :
await self . clock . sleep ( 1.0 )
return HTTPStatus . OK , b " ok "
2022-06-07 11:17:32 -06:00
class DirectServeJsonResourceCancellationTests ( unittest . TestCase ) :
2022-05-11 05:24:48 -06:00
""" Tests for `DirectServeJsonResource` cancellation. """
2022-06-28 06:12:17 -06:00
def setUp ( self ) - > None :
2023-07-18 02:49:21 -06:00
reactor , clock = get_clock ( )
self . reactor = reactor
self . resource = CancellableDirectServeJsonResource ( clock )
2022-05-11 05:24:48 -06:00
self . site = FakeSite ( self . resource , self . reactor )
def test_cancellable_disconnect ( self ) - > None :
""" Test that handlers with the `@cancellable` flag can be cancelled. """
channel = make_request (
self . reactor , self . site , " GET " , " /sleep " , await_result = False
)
2022-06-07 11:17:32 -06:00
test_disconnect (
2022-05-11 05:24:48 -06:00
self . reactor ,
channel ,
expect_cancellation = True ,
expected_body = { " error " : " Request cancelled " , " errcode " : Codes . UNKNOWN } ,
)
def test_uncancellable_disconnect ( self ) - > None :
""" Test that handlers without the `@cancellable` flag cannot be cancelled. """
channel = make_request (
self . reactor , self . site , " POST " , " /sleep " , await_result = False
)
2022-06-07 11:17:32 -06:00
test_disconnect (
2022-05-11 05:24:48 -06:00
self . reactor ,
channel ,
expect_cancellation = False ,
expected_body = { " result " : True } ,
)
2022-06-07 11:17:32 -06:00
class DirectServeHtmlResourceCancellationTests ( unittest . TestCase ) :
2022-05-11 05:24:48 -06:00
""" Tests for `DirectServeHtmlResource` cancellation. """
2022-06-28 06:12:17 -06:00
def setUp ( self ) - > None :
2023-07-18 02:49:21 -06:00
reactor , clock = get_clock ( )
self . reactor = reactor
self . resource = CancellableDirectServeHtmlResource ( clock )
2022-05-11 05:24:48 -06:00
self . site = FakeSite ( self . resource , self . reactor )
def test_cancellable_disconnect ( self ) - > None :
""" Test that handlers with the `@cancellable` flag can be cancelled. """
channel = make_request (
self . reactor , self . site , " GET " , " /sleep " , await_result = False
)
2022-06-07 11:17:32 -06:00
test_disconnect (
2022-05-11 05:24:48 -06:00
self . reactor ,
channel ,
expect_cancellation = True ,
expected_body = b " 499 Request cancelled " ,
)
def test_uncancellable_disconnect ( self ) - > None :
""" Test that handlers without the `@cancellable` flag cannot be cancelled. """
channel = make_request (
self . reactor , self . site , " POST " , " /sleep " , await_result = False
)
2022-06-07 11:17:32 -06:00
test_disconnect (
2022-05-11 05:24:48 -06:00
self . reactor , channel , expect_cancellation = False , expected_body = b " ok "
)