diff --git a/docs/sanic/streaming.md b/docs/sanic/streaming.md index 4614aa4687..60ff3df3bd 100644 --- a/docs/sanic/streaming.md +++ b/docs/sanic/streaming.md @@ -37,6 +37,7 @@ Sanic allows you to get request data by stream, as below. When the request ends, ``` from sanic import Sanic +from sanic.views import CompositionView from sanic.blueprints import Blueprint from sanic.response import stream, text @@ -71,7 +72,20 @@ async def bp_handler(request): result += body.decode('utf-8').replace('1', 'A') return text(result) + +async def post_handler(request): + result = '' + while True: + body = await request.stream.get() + if body is None: + break + result += body.decode('utf-8') + return text(result) + app.blueprint(bp) +view = CompositionView() +view.add(['POST'], post_handler, stream=True) +app.add_route(view, '/composition_view') if __name__ == '__main__': diff --git a/examples/request_stream/server.py b/examples/request_stream/server.py index e6cf797785..5480dc9040 100644 --- a/examples/request_stream/server.py +++ b/examples/request_stream/server.py @@ -1,4 +1,5 @@ from sanic import Sanic +from sanic.views import CompositionView from sanic.blueprints import Blueprint from sanic.response import stream, text @@ -33,7 +34,20 @@ async def bp_handler(request): result += body.decode('utf-8').replace('1', 'A') return text(result) + +async def post_handler(request): + result = '' + while True: + body = await request.stream.get() + if body is None: + break + result += body.decode('utf-8') + return text(result) + app.blueprint(bp) +view = CompositionView() +view.add(['POST'], post_handler, stream=True) +app.add_route(view, '/composition_view') if __name__ == '__main__': diff --git a/sanic/router.py b/sanic/router.py index 2d9ae616db..c994a81d51 100644 --- a/sanic/router.py +++ b/sanic/router.py @@ -352,4 +352,4 @@ def is_stream_handler(self, request): :return: bool """ handler = self.get(request)[0] - return handler.is_stream + return hasattr(handler, 'is_stream') and handler.is_stream diff --git a/sanic/views.py b/sanic/views.py index bc29bfbcb6..736b38064d 100644 --- a/sanic/views.py +++ b/sanic/views.py @@ -83,7 +83,8 @@ class CompositionView: def __init__(self): self.handlers = {} - def add(self, methods, handler): + def add(self, methods, handler, stream=False): + handler.is_stream = stream for method in methods: if method not in HTTP_METHODS: raise InvalidUsage( diff --git a/tests/test_request_stream.py b/tests/test_request_stream.py index 652299bce0..cf8f7b9903 100644 --- a/tests/test_request_stream.py +++ b/tests/test_request_stream.py @@ -1,11 +1,19 @@ from sanic import Sanic from sanic.blueprints import Blueprint +from sanic.views import CompositionView +from sanic.views import HTTPMethodView from sanic.response import stream, text bp = Blueprint('test_blueprint_request_stream') app = Sanic('test_request_stream') +class SimpleView(HTTPMethodView): + + def get(self, request): + return text('OK') + + @app.stream('/stream') async def handler(request): async def streaming(response): @@ -32,12 +40,44 @@ async def bp_handler(request): result += body.decode('utf-8') return text(result) + +def get_handler(request): + return text('OK') + + +async def post_handler(request): + result = '' + while True: + body = await request.stream.get() + if body is None: + break + result += body.decode('utf-8') + return text(result) + + +app.add_route(SimpleView.as_view(), '/method_view') + +view = CompositionView() +view.add(['GET'], get_handler) +view.add(['POST'], post_handler, stream=True) + app.blueprint(bp) +app.add_route(view, '/composition_view') + def test_request_stream(): data = "abc" * 100000 - request, response = app.test_client.post('/stream', data=data) + + request, response = app.test_client.get('/method_view') + assert response.status == 200 + assert response.text == 'OK' + + request, response = app.test_client.get('/composition_view') + assert response.status == 200 + assert response.text == 'OK' + + request, response = app.test_client.post('/composition_view', data=data) assert response.status == 200 assert response.text == data @@ -45,6 +85,10 @@ def test_request_stream(): assert response.status == 200 assert response.text == 'OK' + request, response = app.test_client.post('/stream', data=data) + assert response.status == 200 + assert response.text == data + request, response = app.test_client.post('/bp_stream', data=data) assert response.status == 200 assert response.text == data