def test_stream_response_writes_correct_content_to_transport(streaming_app): response = StreamingHTTPResponse(sample_streaming_fn) response.protocol = MagicMock(HttpProtocol) response.protocol.transport = MagicMock(asyncio.Transport) async def mock_drain(): pass def mock_push_data(data): response.protocol.transport.write(data) response.protocol.push_data = mock_push_data response.protocol.drain = mock_drain @streaming_app.listener('after_server_start') async def run_stream(app, loop): await response.stream() assert response.protocol.transport.write.call_args_list[1][0][0] == ( b'4\r\nfoo,\r\n') assert response.protocol.transport.write.call_args_list[2][0][0] == ( b'3\r\nbar\r\n') assert response.protocol.transport.write.call_args_list[3][0][0] == ( b'0\r\n\r\n') app.stop() streaming_app.run(host=HOST, port=PORT)
def test_stream_response_keep_alive_returns_correct_headers( keep_alive_timeout): response = StreamingHTTPResponse(sample_streaming_fn) headers = response.get_headers(keep_alive=True, keep_alive_timeout=keep_alive_timeout) assert b"Keep-Alive: %s\r\n" % str(keep_alive_timeout).encode() in headers
def test_stream_response_keep_alive_returns_correct_headers( keep_alive_timeout): response = StreamingHTTPResponse(sample_streaming_fn) headers = response.get_headers( keep_alive=True, keep_alive_timeout=keep_alive_timeout) assert b"Keep-Alive: %s\r\n" % str(keep_alive_timeout).encode() in headers
def test_stream_response_writes_correct_content_to_transport_when_not_chunked( streaming_app, ): response = StreamingHTTPResponse(sample_streaming_fn) response.protocol = MagicMock(HttpProtocol) response.protocol.transport = MagicMock(asyncio.Transport) async def mock_drain(): pass def mock_push_data(data): response.protocol.transport.write(data) response.protocol.push_data = mock_push_data response.protocol.drain = mock_drain @streaming_app.listener("after_server_start") async def run_stream(app, loop): await response.stream(version="1.0") assert response.protocol.transport.write.call_args_list[1][0][0] == ( b"foo," ) assert response.protocol.transport.write.call_args_list[2][0][0] == ( b"bar" ) assert len(response.protocol.transport.write.call_args_list) == 3 app.stop() streaming_app.run(host=HOST, port=PORT)
async def process(self): request = self.request headers = ( ('Connection', request.headers.get('Connection', "close")), ('Content-Type', "application/javascript; charset=UTF-8"), ('Cache-Control', CACHE_CONTROL), ) headers += session_cookie(request) headers += cors_headers(request.headers) if request.method == 'OPTIONS': headers += (('Access-Control-Allow-Methods', "OPTIONS, POST"), ) headers += cache_headers() return HTTPResponse(None, status=204, headers=headers) async def stream(_response): nonlocal self self.response = _response await _response.write(self.open_seq) # event loop await self.handle_session() # open sequence (sockjs protocol) return StreamingHTTPResponse(stream, headers=headers)
async def process(self): request = self.request if request.method == 'OPTIONS': headers = ( ('Content-Type', "application/javascript; charset=UTF-8"), ('Access-Control-Allow-Methods', "OPTIONS, POST"), ) headers += session_cookie(request) headers += cors_headers(request.headers) headers += cache_headers() return HTTPResponse(None, status=204, headers=headers) headers = ( ('Content-Type', "application/javascript; charset=UTF-8"), ('Cache-Control', CACHE_CONTROL), ) headers += session_cookie(request) headers += cors_headers(request.headers) async def stream(_response): nonlocal self self.response = _response await self.handle_session() return StreamingHTTPResponse(stream, headers=headers)
async def process(self): request = self.request try: callback = request.query_args.get("c", None) except Exception: callback = request.args.get("c", None) if callback is None: await self.session._remote_closed() raise exceptions.ServerError('"callback" parameter required') elif not self.check_callback.match(callback): await self.session._remote_closed() raise exceptions.ServerError('invalid "callback" parameter') headers = ( ('Content-Type', "text/html; charset=UTF-8"), ('Cache-Control', CACHE_CONTROL), ('Connection', "close"), ) headers += session_cookie(request) headers += cors_headers(request.headers) async def stream(_response): nonlocal self self.response = _response await _response.write(b"".join( (PRELUDE1, callback.encode("utf-8"), PRELUDE2, b" " * 1024))) # handle session await self.handle_session() # open sequence (sockjs protocol) return StreamingHTTPResponse(stream, headers=headers)
async def test_handle_session_interrupted(make_transport, make_fut): trans = make_transport() trans.session.interrupted = True trans.send = make_fut(1) trans.response = StreamingHTTPResponse(make_fut(0)) await trans.handle_session() trans.send.assert_called_with('c[1002,"Connection interrupted"]')
def sendAudioFiles(self, location): status = 200 chunk_size = 4096 mime_type = None headers = None filename = None chunked = True _range = None """Return a streaming response object with file data. :param location: Location of file on system. :param chunk_size: The size of each chunk in the stream (in bytes) :param mime_type: Specific mime_type. :param headers: Custom Headers. :param filename: Override filename. :param chunked: Enable or disable chunked transfer-encoding :param _range: """ headers = headers or {} if filename: headers.setdefault("Content-Disposition", f'attachment; filename="{filename}"') filename = filename or path.split(location)[-1] mime_type = mime_type or guess_type(filename)[0] or "text/plain" if _range: start = _range.start end = _range.end total = _range.total headers["Content-Range"] = f"bytes {start}-{end}/{total}" status = 206 async def _streaming_fn(response): async with await open_async(location, mode="rb") as f: if _range: await f.seek(_range.start) to_send = _range.size while to_send > 0: content = await f.read(min((_range.size, chunk_size))) if len(content) < 1: break to_send -= len(content) await response.write(content) else: while True: content = await f.read(chunk_size) if len(content) < 1: break await response.write(content) return StreamingHTTPResponse( streaming_fn=_streaming_fn, status=status, headers=headers, content_type=mime_type, chunked=chunked, )
async def wrapped(*args, **kwargs): if asyncio.iscoroutinefunction(func): coro = func else: coro = asyncio.coroutine(func) context = await coro(*args, **kwargs) # wrapped function return HTTPResponse # instead of dict-like object if isinstance(context, HTTPResponse): return context # wrapped function is class method # and got `self` as first argument if isinstance(args[0], HTTPMethodView): request = args[1] else: request = args[0] if context is None: context = {} env = getattr(request.app, 'jinja_env', None) if not env: raise ServerError( "Template engine has not been initialized yet.", status_code=500, ) try: template = env.get_template(template_name) except TemplateNotFound as e: raise ServerError( "Template '{}' not found".format(template_name), status_code=500, ) if not isinstance(context, Mapping): raise ServerError( "context should be mapping, not {}".format( type(context)), status_code=500, ) # if request.get(REQUEST_CONTEXT_KEY): # context = dict(request[REQUEST_CONTEXT_KEY], **context) update_request_context(request, context) content_type = "text/html; charset={}".format(encoding) async def do_response(response): async for chunk in template.generate_async(context): await response.write(chunk) return StreamingHTTPResponse( do_response, status=status, headers=headers, content_type=content_type )
def test_stream_response_writes_correct_content_to_transport(streaming_app): response = StreamingHTTPResponse(sample_streaming_fn) response.transport = MagicMock(asyncio.Transport) @streaming_app.listener('after_server_start') async def run_stream(app, loop): await response.stream() assert response.transport.write.call_args_list[1][0][0] == ( b'4\r\nfoo,\r\n') assert response.transport.write.call_args_list[2][0][0] == ( b'3\r\nbar\r\n') assert response.transport.write.call_args_list[3][0][0] == ( b'0\r\n\r\n') app.stop() streaming_app.run(host=HOST, port=PORT)
async def test_handle_session_closed(make_transport, make_fut): trans = make_transport() trans.send = make_fut(1) trans.session.interrupted = False trans.session.state = protocol.STATE_CLOSED trans.session._remote_closed = make_fut(1) trans.response = StreamingHTTPResponse(make_fut(0)) await trans.handle_session() trans.session._remote_closed.assert_called_with() trans.send.assert_called_with('c[3000,"Go away!"]')
def test_stream_response_writes_correct_content_to_transport(streaming_app): response = StreamingHTTPResponse(sample_streaming_fn) response.transport = MagicMock(asyncio.Transport) @streaming_app.listener('after_server_start') async def run_stream(app, loop): await response.stream() assert response.transport.write.call_args_list[1][0][0] == ( b'4\r\nfoo,\r\n' ) assert response.transport.write.call_args_list[2][0][0] == ( b'3\r\nbar\r\n' ) assert response.transport.write.call_args_list[3][0][0] == ( b'0\r\n\r\n' ) app.stop() streaming_app.run(host=HOST, port=PORT)
def test_on_response_streaming_http_response(): class MockRequest: method = 'GET' url = 'http://localhost' req = MockRequest() resp = StreamingHTTPResponse(None) contextvars.bind_contextvars(request_id='test-request', ) ctx = contextvars._CONTEXT_VARS assert 'test-request' == ctx['structlog_request_id'].get() app.on_response(req, resp) ctx = contextvars._CONTEXT_VARS assert ctx['structlog_request_id'].get() is Ellipsis
async def process(self): headers = ( ('Content-Type', "text/event-stream"), ('Cache-Control', CACHE_CONTROL), ) headers += session_cookie(self.request) async def stream(_response): nonlocal self self.response = _response await _response.write(b"\r\n") # handle session await self.handle_session() # open sequence (sockjs protocol) return StreamingHTTPResponse(stream, headers=headers)
def test_stream_response_includes_chunked_header(): response = StreamingHTTPResponse(sample_streaming_fn) headers = response.get_headers() assert b"Transfer-Encoding: chunked\r\n" in headers
def test_stream_response_status_returns_correct_headers(status): response = StreamingHTTPResponse(sample_streaming_fn, status=status) headers = response.get_headers() assert b"HTTP/1.1 %s" % str(status).encode() in headers
async def process(self): session = self.session request = self.request meth = request.method if request.method == 'GET': try: callback = self.callback = request.query_args.get("c") except Exception: callback = self.callback = request.args.get("c", None) if not callback: await self.session._remote_closed() raise exceptions.ServerError('"callback" parameter required') elif not self.check_callback.match(callback): await self.session._remote_closed() raise exceptions.ServerError('invalid "callback" parameter') headers = ( ('Content-Type', "application/javascript; charset=UTF-8"), ('Cache-Control', CACHE_CONTROL), ) headers += session_cookie(request) headers += cors_headers(request.headers) async def stream(_response): nonlocal self self.response = _response # handle session await self.handle_session() # open sequence (sockjs protocol) return StreamingHTTPResponse(stream, headers=headers) elif request.method == 'POST': data = await request.stream.read() ctype = request.content_type.lower() if ctype == "application/x-www-form-urlencoded": if not data.startswith(b"d="): raise exceptions.ServerError("Payload expected.") data = unquote_plus(data[2:].decode(ENCODING)) else: data = data.decode(ENCODING) if not data: raise exceptions.ServerError("Payload expected.") try: messages = loads(data) except Exception: raise exceptions.ServerError("Broken JSON encoding.") await session._remote_messages(messages) headers = ( ('Content-Type', "text/html;charset=UTF-8"), ('Cache-Control', CACHE_CONTROL), ) headers += session_cookie(request) return HTTPResponse(None, body_bytes=b"ok", headers=headers) else: raise exceptions.MethodNotSupported( "No support for such method: %s" % meth, meth, ('GET', 'POST'))
def test_stream_response_does_not_include_chunked_header_http10(): response = StreamingHTTPResponse(sample_streaming_fn) headers = response.get_headers(version="1.0") assert b"Transfer-Encoding: chunked\r\n" not in headers
def test_stream_response_does_not_include_chunked_header_if_disabled(): response = StreamingHTTPResponse(sample_streaming_fn, chunked=False) headers = response.get_headers(version="1.1") assert b"Transfer-Encoding: chunked\r\n" not in headers