Merge pull request #1423 from yunstanford/request-streaming-support
basic request streaming support with flow control
This commit is contained in:
commit
67d51f7e1b
55
README.rst
55
README.rst
|
@ -1,7 +1,44 @@
|
||||||
Sanic
|
Sanic
|
||||||
=====
|
=====
|
||||||
|
|
||||||
|Join the chat at https://gitter.im/sanic-python/Lobby| |Build Status| |AppVeyor Build Status| |Documentation| |Codecov| |PyPI| |PyPI version| |Code style black|
|
.. start-badges
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
:stub-columns: 1
|
||||||
|
|
||||||
|
* - Build
|
||||||
|
- | |Build Status| |AppVeyor Build Status| |Codecov|
|
||||||
|
* - Docs
|
||||||
|
- |Documentation|
|
||||||
|
* - Package
|
||||||
|
- | |PyPI| |PyPI version| |Wheel| |Supported implementations| |Code style black|
|
||||||
|
* - Support
|
||||||
|
- |Join the chat at https://gitter.im/sanic-python/Lobby|
|
||||||
|
|
||||||
|
.. |Join the chat at https://gitter.im/sanic-python/Lobby| image:: https://badges.gitter.im/sanic-python/Lobby.svg
|
||||||
|
:target: https://gitter.im/sanic-python/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
||||||
|
.. |Codecov| image:: https://codecov.io/gh/huge-success/sanic/branch/master/graph/badge.svg
|
||||||
|
:target: https://codecov.io/gh/huge-success/sanic
|
||||||
|
.. |Build Status| image:: https://travis-ci.org/huge-success/sanic.svg?branch=master
|
||||||
|
:target: https://travis-ci.org/huge-success/sanic
|
||||||
|
.. |AppVeyor Build Status| image:: https://ci.appveyor.com/api/projects/status/d8pt3ids0ynexi8c/branch/master?svg=true
|
||||||
|
:target: https://ci.appveyor.com/project/huge-success/sanic
|
||||||
|
.. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest
|
||||||
|
:target: http://sanic.readthedocs.io/en/latest/?badge=latest
|
||||||
|
.. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg
|
||||||
|
:target: https://pypi.python.org/pypi/sanic/
|
||||||
|
.. |PyPI version| image:: https://img.shields.io/pypi/pyversions/sanic.svg
|
||||||
|
:target: https://pypi.python.org/pypi/sanic/
|
||||||
|
.. |Code style black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||||
|
:target: https://github.com/ambv/black
|
||||||
|
.. |Wheel| image:: https://img.shields.io/pypi/wheel/sanic.svg
|
||||||
|
:alt: PyPI Wheel
|
||||||
|
:target: https://pypi.python.org/pypi/sanic
|
||||||
|
.. |Supported implementations| image:: https://img.shields.io/pypi/implementation/sanic.svg
|
||||||
|
:alt: Supported implementations
|
||||||
|
:target: https://pypi.python.org/pypi/sanic
|
||||||
|
|
||||||
|
.. end-badges
|
||||||
|
|
||||||
Sanic is a Flask-like Python 3.5+ web server that's written to go fast. It's based on the work done by the amazing folks at magicstack, and was inspired by `this article <https://magic.io/blog/uvloop-blazing-fast-python-networking/>`_.
|
Sanic is a Flask-like Python 3.5+ web server that's written to go fast. It's based on the work done by the amazing folks at magicstack, and was inspired by `this article <https://magic.io/blog/uvloop-blazing-fast-python-networking/>`_.
|
||||||
|
|
||||||
|
@ -45,22 +82,6 @@ Documentation
|
||||||
|
|
||||||
`Documentation on Readthedocs <http://sanic.readthedocs.io/>`_.
|
`Documentation on Readthedocs <http://sanic.readthedocs.io/>`_.
|
||||||
|
|
||||||
.. |Join the chat at https://gitter.im/sanic-python/Lobby| image:: https://badges.gitter.im/sanic-python/Lobby.svg
|
|
||||||
:target: https://gitter.im/sanic-python/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
|
||||||
.. |Codecov| image:: https://codecov.io/gh/huge-success/sanic/branch/master/graph/badge.svg
|
|
||||||
:target: https://codecov.io/gh/huge-success/sanic
|
|
||||||
.. |Build Status| image:: https://travis-ci.org/huge-success/sanic.svg?branch=master
|
|
||||||
:target: https://travis-ci.org/huge-success/sanic
|
|
||||||
.. |AppVeyor Build Status| image:: https://ci.appveyor.com/api/projects/status/d8pt3ids0ynexi8c/branch/master?svg=true
|
|
||||||
:target: https://ci.appveyor.com/project/huge-success/sanic
|
|
||||||
.. |Documentation| image:: https://readthedocs.org/projects/sanic/badge/?version=latest
|
|
||||||
:target: http://sanic.readthedocs.io/en/latest/?badge=latest
|
|
||||||
.. |PyPI| image:: https://img.shields.io/pypi/v/sanic.svg
|
|
||||||
:target: https://pypi.python.org/pypi/sanic/
|
|
||||||
.. |PyPI version| image:: https://img.shields.io/pypi/pyversions/sanic.svg
|
|
||||||
:target: https://pypi.python.org/pypi/sanic/
|
|
||||||
.. |Code style black| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
||||||
:target: https://github.com/ambv/black
|
|
||||||
|
|
||||||
Questions and Discussion
|
Questions and Discussion
|
||||||
------------------------
|
------------------------
|
||||||
|
|
|
@ -88,6 +88,7 @@ Out of the box there are just a few predefined values which can be overwritten w
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
| ------------------------- | --------- | ------------------------------------------------------ |
|
| ------------------------- | --------- | ------------------------------------------------------ |
|
||||||
| REQUEST_MAX_SIZE | 100000000 | How big a request may be (bytes) |
|
| REQUEST_MAX_SIZE | 100000000 | How big a request may be (bytes) |
|
||||||
|
| REQUEST_BUFFER_QUEUE_SIZE | 100 | Request streaming buffer queue size |
|
||||||
| REQUEST_TIMEOUT | 60 | How long a request can take to arrive (sec) |
|
| REQUEST_TIMEOUT | 60 | How long a request can take to arrive (sec) |
|
||||||
| RESPONSE_TIMEOUT | 60 | How long a response can take to process (sec) |
|
| RESPONSE_TIMEOUT | 60 | How long a response can take to process (sec) |
|
||||||
| KEEP_ALIVE | True | Disables keep-alive when False |
|
| KEEP_ALIVE | True | Disables keep-alive when False |
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Request Streaming
|
## Request Streaming
|
||||||
|
|
||||||
Sanic allows you to get request data by stream, as below. When the request ends, `request.stream.get()` returns `None`. Only post, put and patch decorator have stream argument.
|
Sanic allows you to get request data by stream, as below. When the request ends, `await request.stream.read()` returns `None`. Only post, put and patch decorator have stream argument.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from sanic import Sanic
|
from sanic import Sanic
|
||||||
|
@ -22,7 +22,7 @@ class SimpleView(HTTPMethodView):
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
@ -33,7 +33,7 @@ class SimpleView(HTTPMethodView):
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
body = body.decode('utf-8').replace('1', 'A')
|
body = body.decode('utf-8').replace('1', 'A')
|
||||||
|
@ -45,7 +45,7 @@ async def handler(request):
|
||||||
async def bp_handler(request):
|
async def bp_handler(request):
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8').replace('1', 'A')
|
result += body.decode('utf-8').replace('1', 'A')
|
||||||
|
@ -55,7 +55,7 @@ async def bp_handler(request):
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
|
|
@ -1071,6 +1071,7 @@ class Sanic:
|
||||||
"response_timeout": self.config.RESPONSE_TIMEOUT,
|
"response_timeout": self.config.RESPONSE_TIMEOUT,
|
||||||
"keep_alive_timeout": self.config.KEEP_ALIVE_TIMEOUT,
|
"keep_alive_timeout": self.config.KEEP_ALIVE_TIMEOUT,
|
||||||
"request_max_size": self.config.REQUEST_MAX_SIZE,
|
"request_max_size": self.config.REQUEST_MAX_SIZE,
|
||||||
|
"request_buffer_queue_size": self.config.REQUEST_BUFFER_QUEUE_SIZE,
|
||||||
"keep_alive": self.config.KEEP_ALIVE,
|
"keep_alive": self.config.KEEP_ALIVE,
|
||||||
"loop": loop,
|
"loop": loop,
|
||||||
"register_sys_signals": register_sys_signals,
|
"register_sys_signals": register_sys_signals,
|
||||||
|
|
|
@ -32,6 +32,7 @@ class Config(dict):
|
||||||
▀▀▄▄▀
|
▀▀▄▄▀
|
||||||
"""
|
"""
|
||||||
self.REQUEST_MAX_SIZE = 100000000 # 100 megabytes
|
self.REQUEST_MAX_SIZE = 100000000 # 100 megabytes
|
||||||
|
self.REQUEST_BUFFER_QUEUE_SIZE = 100
|
||||||
self.REQUEST_TIMEOUT = 60 # 60 seconds
|
self.REQUEST_TIMEOUT = 60 # 60 seconds
|
||||||
self.RESPONSE_TIMEOUT = 60 # 60 seconds
|
self.RESPONSE_TIMEOUT = 60 # 60 seconds
|
||||||
self.KEEP_ALIVE = keep_alive
|
self.KEEP_ALIVE = keep_alive
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
@ -47,6 +48,23 @@ class RequestParameters(dict):
|
||||||
return super().get(name, default)
|
return super().get(name, default)
|
||||||
|
|
||||||
|
|
||||||
|
class StreamBuffer:
|
||||||
|
def __init__(self, buffer_size=100):
|
||||||
|
self._queue = asyncio.Queue(buffer_size)
|
||||||
|
|
||||||
|
async def read(self):
|
||||||
|
""" Stop reading when gets None """
|
||||||
|
payload = await self._queue.get()
|
||||||
|
self._queue.task_done()
|
||||||
|
return payload
|
||||||
|
|
||||||
|
async def put(self, payload):
|
||||||
|
await self._queue.put(payload)
|
||||||
|
|
||||||
|
def is_full(self):
|
||||||
|
return self._queue.full()
|
||||||
|
|
||||||
|
|
||||||
class Request(dict):
|
class Request(dict):
|
||||||
"""Properties of an HTTP request such as URL, headers, etc."""
|
"""Properties of an HTTP request such as URL, headers, etc."""
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ from sanic.exceptions import (
|
||||||
ServiceUnavailable,
|
ServiceUnavailable,
|
||||||
)
|
)
|
||||||
from sanic.log import access_logger, logger
|
from sanic.log import access_logger, logger
|
||||||
from sanic.request import Request
|
from sanic.request import Request, StreamBuffer
|
||||||
from sanic.response import HTTPResponse
|
from sanic.response import HTTPResponse
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
"response_timeout",
|
"response_timeout",
|
||||||
"keep_alive_timeout",
|
"keep_alive_timeout",
|
||||||
"request_max_size",
|
"request_max_size",
|
||||||
|
"request_buffer_queue_size",
|
||||||
"request_class",
|
"request_class",
|
||||||
"is_request_stream",
|
"is_request_stream",
|
||||||
"router",
|
"router",
|
||||||
|
@ -89,11 +90,12 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
request_handler,
|
request_handler,
|
||||||
error_handler,
|
error_handler,
|
||||||
signal=Signal(),
|
signal=Signal(),
|
||||||
connections=set(),
|
connections=None,
|
||||||
request_timeout=60,
|
request_timeout=60,
|
||||||
response_timeout=60,
|
response_timeout=60,
|
||||||
keep_alive_timeout=5,
|
keep_alive_timeout=5,
|
||||||
request_max_size=None,
|
request_max_size=None,
|
||||||
|
request_buffer_queue_size=100,
|
||||||
request_class=None,
|
request_class=None,
|
||||||
access_log=True,
|
access_log=True,
|
||||||
keep_alive=True,
|
keep_alive=True,
|
||||||
|
@ -112,10 +114,11 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self.router = router
|
self.router = router
|
||||||
self.signal = signal
|
self.signal = signal
|
||||||
self.access_log = access_log
|
self.access_log = access_log
|
||||||
self.connections = connections
|
self.connections = connections or set()
|
||||||
self.request_handler = request_handler
|
self.request_handler = request_handler
|
||||||
self.error_handler = error_handler
|
self.error_handler = error_handler
|
||||||
self.request_timeout = request_timeout
|
self.request_timeout = request_timeout
|
||||||
|
self.request_buffer_queue_size = request_buffer_queue_size
|
||||||
self.response_timeout = response_timeout
|
self.response_timeout = response_timeout
|
||||||
self.keep_alive_timeout = keep_alive_timeout
|
self.keep_alive_timeout = keep_alive_timeout
|
||||||
self.request_max_size = request_max_size
|
self.request_max_size = request_max_size
|
||||||
|
@ -298,17 +301,27 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self.request
|
self.request
|
||||||
)
|
)
|
||||||
if self._is_stream_handler:
|
if self._is_stream_handler:
|
||||||
self.request.stream = asyncio.Queue()
|
self.request.stream = StreamBuffer(
|
||||||
|
self.request_buffer_queue_size
|
||||||
|
)
|
||||||
self.execute_request_handler()
|
self.execute_request_handler()
|
||||||
|
|
||||||
def on_body(self, body):
|
def on_body(self, body):
|
||||||
if self.is_request_stream and self._is_stream_handler:
|
if self.is_request_stream and self._is_stream_handler:
|
||||||
self._request_stream_task = self.loop.create_task(
|
self._request_stream_task = self.loop.create_task(
|
||||||
self.request.stream.put(body)
|
self.body_append(body)
|
||||||
)
|
)
|
||||||
return
|
else:
|
||||||
self.request.body_push(body)
|
self.request.body_push(body)
|
||||||
|
|
||||||
|
async def body_append(self, body):
|
||||||
|
if self.request.stream.is_full():
|
||||||
|
self.transport.pause_reading()
|
||||||
|
await self.request.stream.put(body)
|
||||||
|
self.transport.resume_reading()
|
||||||
|
else:
|
||||||
|
await self.request.stream.put(body)
|
||||||
|
|
||||||
def on_message_complete(self):
|
def on_message_complete(self):
|
||||||
# Entire request (headers and whole body) is received.
|
# Entire request (headers and whole body) is received.
|
||||||
# We can cancel and remove the request timeout handler now.
|
# We can cancel and remove the request timeout handler now.
|
||||||
|
@ -575,6 +588,7 @@ def serve(
|
||||||
ssl=None,
|
ssl=None,
|
||||||
sock=None,
|
sock=None,
|
||||||
request_max_size=None,
|
request_max_size=None,
|
||||||
|
request_buffer_queue_size=100,
|
||||||
reuse_port=False,
|
reuse_port=False,
|
||||||
loop=None,
|
loop=None,
|
||||||
protocol=HttpProtocol,
|
protocol=HttpProtocol,
|
||||||
|
@ -635,6 +649,7 @@ def serve(
|
||||||
outgoing bytes, the low-water limit is a
|
outgoing bytes, the low-water limit is a
|
||||||
quarter of the high-water limit.
|
quarter of the high-water limit.
|
||||||
:param is_request_stream: disable/enable Request.stream
|
:param is_request_stream: disable/enable Request.stream
|
||||||
|
:param request_buffer_queue_size: streaming request buffer queue size
|
||||||
:param router: Router object
|
:param router: Router object
|
||||||
:param graceful_shutdown_timeout: How long take to Force close non-idle
|
:param graceful_shutdown_timeout: How long take to Force close non-idle
|
||||||
connection
|
connection
|
||||||
|
|
|
@ -4,8 +4,10 @@ from sanic.views import CompositionView
|
||||||
from sanic.views import HTTPMethodView
|
from sanic.views import HTTPMethodView
|
||||||
from sanic.views import stream as stream_decorator
|
from sanic.views import stream as stream_decorator
|
||||||
from sanic.response import stream, text
|
from sanic.response import stream, text
|
||||||
|
from sanic.request import StreamBuffer
|
||||||
|
|
||||||
data = "abc" * 100000
|
|
||||||
|
data = "abc" * 10000000
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_method_view(app):
|
def test_request_stream_method_view(app):
|
||||||
|
@ -19,10 +21,10 @@ def test_request_stream_method_view(app):
|
||||||
|
|
||||||
@stream_decorator
|
@stream_decorator
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
@ -71,11 +73,11 @@ def test_request_stream_app(app):
|
||||||
|
|
||||||
@app.post('/post/<id>', stream=True)
|
@app.post('/post/<id>', stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -88,11 +90,11 @@ def test_request_stream_app(app):
|
||||||
|
|
||||||
@app.put('/put', stream=True)
|
@app.put('/put', stream=True)
|
||||||
async def put(request):
|
async def put(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -105,11 +107,11 @@ def test_request_stream_app(app):
|
||||||
|
|
||||||
@app.patch('/patch', stream=True)
|
@app.patch('/patch', stream=True)
|
||||||
async def patch(request):
|
async def patch(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -163,11 +165,11 @@ def test_request_stream_handle_exception(app):
|
||||||
|
|
||||||
@app.post('/post/<id>', stream=True)
|
@app.post('/post/<id>', stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -216,11 +218,11 @@ def test_request_stream_blueprint(app):
|
||||||
|
|
||||||
@bp.post('/post/<id>', stream=True)
|
@bp.post('/post/<id>', stream=True)
|
||||||
async def post(request, id):
|
async def post(request, id):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -233,11 +235,11 @@ def test_request_stream_blueprint(app):
|
||||||
|
|
||||||
@bp.put('/put', stream=True)
|
@bp.put('/put', stream=True)
|
||||||
async def put(request):
|
async def put(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -250,11 +252,11 @@ def test_request_stream_blueprint(app):
|
||||||
|
|
||||||
@bp.patch('/patch', stream=True)
|
@bp.patch('/patch', stream=True)
|
||||||
async def patch(request):
|
async def patch(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -313,10 +315,10 @@ def test_request_stream_composition_view(app):
|
||||||
return text('OK')
|
return text('OK')
|
||||||
|
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
@ -350,10 +352,10 @@ def test_request_stream(app):
|
||||||
|
|
||||||
@stream_decorator
|
@stream_decorator
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
@ -361,11 +363,11 @@ def test_request_stream(app):
|
||||||
|
|
||||||
@app.post('/stream', stream=True)
|
@app.post('/stream', stream=True)
|
||||||
async def handler(request):
|
async def handler(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
|
|
||||||
async def streaming(response):
|
async def streaming(response):
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
await response.write(body.decode('utf-8'))
|
await response.write(body.decode('utf-8'))
|
||||||
|
@ -378,10 +380,10 @@ def test_request_stream(app):
|
||||||
|
|
||||||
@bp.post('/bp_stream', stream=True)
|
@bp.post('/bp_stream', stream=True)
|
||||||
async def bp_stream(request):
|
async def bp_stream(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
@ -397,10 +399,10 @@ def test_request_stream(app):
|
||||||
return text('OK')
|
return text('OK')
|
||||||
|
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
assert isinstance(request.stream, asyncio.Queue)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ''
|
result = ''
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.get()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode('utf-8')
|
result += body.decode('utf-8')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user