async def test_cookies_jar_single_cookie(): fake_pools = FakePools([ Response(200, [ (b"Set-Cookie", write_response_cookie(Cookie(b"X-Foo", b"Foo"))) ]).with_content(TextContent("Hello, World!")), Response(200, None, TextContent("Hello!")), ]) check_cookie = False async def middleware_for_assertions(request, next_handler): if check_cookie: cookie = request.cookies.get("X-Foo") assert (cookie is not None ), "X-Foo cookie must be configured for following requests" return await next_handler(request) async with ClientSession( base_url=b"https://bezkitu.org", pools=fake_pools, middlewares=[middleware_for_assertions], ) as client: await client.get( b"/" ) # the first request doesn't have any cookie because the response will set; check_cookie = True await client.get(b"/")
def get_response_for_file(request, resource_path: str, cache_time: int): stat = os.stat(resource_path) file_size = stat.st_size modified_time = stat.st_mtime current_etag = str(modified_time).encode() previous_etag = request.if_none_match headers = [ (b'Last-Modified', unix_timestamp_to_datetime(modified_time)), (b'ETag', current_etag) ] if cache_time > 0: headers.append((b'Cache-Control', b'max-age=' + str(cache_time).encode())) if previous_etag and current_etag == previous_etag: return Response(304, headers, None) if request.method == 'HEAD': headers.append((b'Content-Type', get_mime_type(resource_path))) headers.append((b'Content-Length', str(file_size).encode())) return Response(200, headers, None) return Response(200, headers, StreamedContent(get_mime_type(resource_path), get_file_data(resource_path, file_size)))
async def echo_headers(request): response = Response(200) for header in request.headers: response.add_header(header[0], header[1]) return response
async def test_cookies_jar(first_request_url, second_request_url, set_cookies, expected_cookies): fake_pools = FakePools([ Response(200, Headers(set_cookies), TextContent('Hello, World!')), Response(200, Headers(), TextContent('Hello!')) ]) check_cookie = False async def middleware_for_assertions(request, next_handler): if check_cookie: if not expected_cookies: assert not request.cookies for expected_cookie in expected_cookies: cookie = request.cookies.get(expected_cookie) assert cookie is not None, f'{cookie.name.decode()} cookie must be configured for following requests' return await next_handler(request) async with ClientSession( pools=fake_pools, middlewares=[middleware_for_assertions], ) as client: await client.get(first_request_url) check_cookie = True await client.get(second_request_url)
async def test_cookies_jar_single_cookie(): fake_pools = FakePools([ Response( 200, Headers([ Header(b'Set-Cookie', write_response_cookie(Cookie(b'X-Foo', b'Foo'))) ]), TextContent('Hello, World!')), Response(200, Headers(), TextContent('Hello!')) ]) check_cookie = False async def middleware_for_assertions(request, next_handler): if check_cookie: cookie = request.cookies.get(b'X-Foo') assert cookie is not None, 'X-Foo cookie must be configured for following requests' return await next_handler(request) async with ClientSession(url=b'https://bezkitu.org', pools=fake_pools, middlewares=[middleware_for_assertions ]) as client: await client.get( b'/' ) # the first request doesn't have any cookie because the response will set; check_cookie = True await client.get(b'/')
def test_response_supports_dynamic_attributes(): response = Response(200) foo = object() assert hasattr(response, 'response') is False, 'This test makes sense if such attribute is not defined' response.foo = foo assert response.foo is foo
def get_response_for_file(request, resource_path, cache_time): # TODO: support for accept-range and bytes ranges file_size = os.path.getsize(resource_path) modified_time = os.path.getmtime(resource_path) current_etag = str(modified_time).encode() previous_etag = request.if_none_match headers = [ Header(b'Last-Modified', unix_timestamp_to_datetime(modified_time)), Header(b'ETag', current_etag) ] if cache_time > 0: headers.append( Header(b'Cache-Control', b'max-age=' + str(cache_time).encode())) if previous_etag and current_etag == previous_etag: return Response(304, headers, None) if request.method == b'HEAD': headers.append(Header(b'Content-Type', get_mime_type(resource_path))) headers.append(Header(b'Content-Length', str(file_size).encode())) return Response(200, headers, None) return Response( 200, Headers(headers), Content(get_mime_type(resource_path), get_file_data(resource_path, file_size)))
def test_response_supports_dynamic_attributes(): response = Response(200) foo = object() assert (hasattr(response, "response") is False), "This test makes sense if such attribute is not defined" response.foo = foo # type: ignore assert response.foo is foo # type: ignore
def on_headers_complete(self): status = self.parser.get_status_code() self.response = Response( status, Headers(self.headers), None ) self.response_ready.set()
def status_code(status: int = 200, message: Any = None) -> Response: """ Returns a plain response with given status, with optional message; sent as plain text or JSON. """ if not message: return Response(status) return Response(status, content=_optional_content(message))
def on_headers_complete(self) -> None: status = self.parser.get_status_code() self.response = Response(status, self.headers, None) # NB: check if headers declare a content-length if self._has_content(): self.response.content = IncomingContent( self.response.get_single_header(b"content-type")) self.response_ready.set()
def status_code(status: int = 200, message: MessageType = None): """Returns a plain response with given status, with optional message; sent as plain text or JSON.""" if not message: return Response(status) if isinstance(message, str): content = TextContent(message) else: content = JsonContent(message) return Response(status, content=content)
async def frozen_file_getter(request): previous_etag = request.if_none_match if previous_etag and previous_etag == current_etag: return Response(304, headers, None) if request.method == b'HEAD': return Response(200, head_headers, None) return Response(200, Headers(headers), Content(mime, data))
def test_is_redirect(): # 301 Moved Permanently # 302 Found # 303 See Other # 307 Temporary Redirect # 308 Permanent Redirect for status in range(200, 500): response = Response(status) is_redirect = status in {301, 302, 303, 307, 308} assert response.is_redirect() == is_redirect
async def static_files_handler(request: Request) -> Response: assert request.route_values is not None, "Expects a route pattern with star *" tail = unquote(request.route_values.get("tail", "")).lstrip("/") try: return get_response_for_resource_path( request, tail, files_list_html, source_folder_name, files_handler, source_folder_full_path, discovery, cache_time, extensions, root_path, index_document, ) except NotFound: if fallback_document is None: return Response(404) return get_response_for_resource_path( request, fallback_document, files_list_html, source_folder_name, files_handler, source_folder_full_path, discovery, cache_time, extensions, root_path, None, )
def html(value: str, status: int = 200) -> Response: """ Returns a response with text/html content, and given status (default HTTP 200 OK). """ return Response(status, None, Content(b"text/html; charset=utf-8", value.encode("utf8")))
async def multiple_db_queries_test(request): """Test type 3: Multiple Database Queries""" num_queries = get_num_queries(request) row_ids = [randint(1, 10000) for _ in range(num_queries)] worlds = [] connection = await db_pool.acquire() try: statement = await connection.prepare( 'SELECT "randomnumber" FROM "world" WHERE id = $1' ) for row_id in row_ids: number = await statement.fetchval(row_id) worlds.append({"id": row_id, "randomNumber": number}) finally: await db_pool.release(connection) return Response( 200, content=Content( b"application/json; charset=utf-8", json_dumps(worlds).encode("utf-8") ), )
async def test_multiple_middleware(): fake_pools = FakePools([Response(200, None, TextContent("Hello, World!"))]) steps = [] async def middleware_one(request, next_handler): steps.append(1) response = await next_handler(request) steps.append(2) return response async def middleware_two(request, next_handler): steps.append(3) response = await next_handler(request) steps.append(4) return response async def middleware_three(request, next_handler): steps.append(5) response = await next_handler(request) steps.append(6) return response async with ClientSession( base_url=b"http://localhost:8080", pools=fake_pools, middlewares=[middleware_one, middleware_two, middleware_three], ) as client: response = await client.get(b"/") assert steps == [1, 3, 5, 6, 4, 2] assert response.status == 200 text = await response.text() assert text == "Hello, World!"
def get_files_list_html_response( template: str, parent_folder_path: str, contents: Sequence[Dict[str, str]], root_path: str, ) -> Response: info_lines = [] for item in contents: rel_path = item.get("rel_path") assert rel_path is not None full_rel_path = html.escape( join_fragments(root_path, parent_folder_path, rel_path)) info_lines.append( f'<li><a href="/{full_rel_path}">{rel_path}</a></li>') info = "".join(info_lines) p = [] whole_p = [root_path] for fragment in parent_folder_path.split("/"): if fragment: whole_p.append(html.escape(fragment)) fragment_path = "/".join(whole_p) p.append(f'<a href="/{fragment_path}">{html.escape(fragment)}</a>') # TODO: use chunked encoding here, yielding HTML fragments return Response( 200, content=HtmlContent( template.format_map({ "path": "/".join(p), "info": info })), )
async def db_updates_test(request): """Test type 5: Database Updates""" num_queries = get_num_queries(request) updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)] worlds = [{ 'id': row_id, 'randomNumber': number } for row_id, number in updates] connection = await db_pool.acquire() try: statement = await connection.prepare( 'SELECT "randomnumber" FROM "world" WHERE id = $1') for row_id, _ in updates: await statement.fetchval(row_id) await connection.executemany( 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2', updates) finally: await db_pool.release(connection) return Response(200, content=Content(b'application/json', json_dumps(worlds).encode('utf-8')))
def test_session_raises_for_redirect_without_location(): """ If a server returns a redirect status without location response header, the client raises an exception. """ with pytest.raises(MissingLocationForRedirect): ClientSession.extract_redirect_location(Response(http.HTTPStatus.FOUND.value))
async def json_test(request): """Test type 1: JSON Serialization""" return Response(200, content=Content( b'application/json; charset=utf-8', json_dumps({ 'message': 'Hello, world!' }).encode('utf-8')))
async def handle_unauthorized(app: Any, request: Request, http_exception: UnauthorizedError) -> Response: www_authenticate = get_www_authenticated_header_from_generic_unauthorized_error( http_exception) return Response( 401, [www_authenticate] if www_authenticate else None, content=TextContent("Unauthorized"), )
def created(message: Any = None, location: AnyStr = "") -> Response: """ Returns an HTTP 201 Created response, to the given location and with optional JSON content. """ return Response( 201, [(b"Location", _ensure_bytes(location))] if location else [], content=_optional_content(message) if message else None, )
async def json_test(request): """Test type 1: JSON Serialization""" return Response( 200, content=Content( b"application/json; charset=utf-8", json_dumps({"message": "Hello, world!"}).encode("utf-8"), ), )
async def test_remove_cookie_with_expiration(): expire_cookie = Cookie(b'X-Foo', b'Foo') expire_cookie.expiration = datetime.utcnow() + timedelta(days=-2) fake_pools = FakePools([ Response( 200, Headers([ Header(b'Set-Cookie', write_response_cookie(Cookie(b'X-Foo', b'Foo'))) ]), TextContent('Hello, World!')), Response(200, Headers(), TextContent('Hello!')), Response( 200, Headers( [Header(b'Set-Cookie', write_response_cookie(expire_cookie))]), TextContent('Hello, World!')), Response(200, Headers(), TextContent('Hello!')) ]) expect_cookie = False async def middleware_for_assertions(request, next_handler): cookie = request.cookies.get(b'X-Foo') if expect_cookie: assert cookie is not None, 'X-Foo cookie must be configured' else: assert cookie is None return await next_handler(request) async with ClientSession(url=b'https://bezkitu.org', pools=fake_pools, middlewares=[middleware_for_assertions ]) as client: await client.get(b'/') # <-- cookie set here expect_cookie = True await client.get(b'/') # <-- expect cookie in request expect_cookie = True await client.get( b'/') # <-- expect cookie in request; it gets removed here expect_cookie = False await client.get( b'/' ) # <-- expect missing cookie; was deleted by previous response
async def test_remove_cookie_with_max_age(): expire_cookie = Cookie("X-Foo", "Foo") expire_cookie.max_age = 0 fake_pools = FakePools( [ Response( 200, [(b"Set-Cookie", write_response_cookie(Cookie("X-Foo", "Foo")))], TextContent("Hello, World!"), ), Response(200, None, TextContent("Hello!")), Response( 200, [(b"Set-Cookie", write_response_cookie(expire_cookie))], TextContent("Hello, World!"), ), Response(200, None, TextContent("Hello!")), ] ) expect_cookie = False async def middleware_for_assertions(request, next_handler): cookie = request.cookies.get("X-Foo") if expect_cookie: assert cookie is not None, "X-Foo cookie must be configured" else: assert cookie is None return await next_handler(request) async with ClientSession( base_url=b"https://bezkitu.org", pools=fake_pools, middlewares=[middleware_for_assertions], ) as client: await client.get(b"/") # <-- cookie set here expect_cookie = True await client.get(b"/") # <-- expect cookie in request expect_cookie = True await client.get(b"/") # <-- expect cookie in request; it gets removed here expect_cookie = False await client.get( b"/" ) # <-- expect missing cookie; was deleted by previous response
def extract_redirect_location(response: Response) -> URL: # if the server returned more than one value, use the first header in order location = response.get_first_header(b'Location') if not location: raise MissingLocationForRedirect(response) # if the location cannot be parsed as URL, let exception happen: this might be a redirect to a URN!! # simply don't follows the redirect, and returns the response to the caller try: return URL(location) except InvalidURL: raise UnsupportedRedirect()
async def create_cat(request): nonlocal called_times called_times += 1 assert request is not None content = await request.read() assert b'{"name":"Celine","kind":"Persian"}' == content data = await request.json() assert {"name": "Celine", "kind": "Persian"} == data return Response(201, [(b'Server', b'Python/3.7')], JsonContent({'id': '123'}))
async def upload_files(request): files = await request.files('files[]') # NB: in this example; we save files to output folder and verify # that their binaries are identical for part in files: full_path = pkg_resources.resource_filename(__name__, 'out/' + part.file_name.decode()) with open(full_path, mode='wb') as saved_file: saved_file.write(part.data) return Response(200)