Make all requests streaming and preload body for non-streaming handlers.
This commit is contained in:
parent
6279eac3d1
commit
fe64a2764d
10
sanic/app.py
10
sanic/app.py
|
@ -82,7 +82,6 @@ class Sanic:
|
||||||
self.strict_slashes = strict_slashes
|
self.strict_slashes = strict_slashes
|
||||||
self.listeners = defaultdict(list)
|
self.listeners = defaultdict(list)
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
self.is_request_stream = False
|
|
||||||
self.websocket_enabled = False
|
self.websocket_enabled = False
|
||||||
self.websocket_tasks = set()
|
self.websocket_tasks = set()
|
||||||
self.named_request_middleware = {}
|
self.named_request_middleware = {}
|
||||||
|
@ -187,9 +186,6 @@ class Sanic:
|
||||||
if not uri.startswith("/"):
|
if not uri.startswith("/"):
|
||||||
uri = "/" + uri
|
uri = "/" + uri
|
||||||
|
|
||||||
if stream:
|
|
||||||
self.is_request_stream = True
|
|
||||||
|
|
||||||
if strict_slashes is None:
|
if strict_slashes is None:
|
||||||
strict_slashes = self.strict_slashes
|
strict_slashes = self.strict_slashes
|
||||||
|
|
||||||
|
@ -956,6 +952,10 @@ class Sanic:
|
||||||
# Fetch handler from router
|
# Fetch handler from router
|
||||||
handler, args, kwargs, uri, name = self.router.get(request)
|
handler, args, kwargs, uri, name = self.router.get(request)
|
||||||
|
|
||||||
|
# Non-streaming handlers have their body preloaded
|
||||||
|
if not self.router.is_stream_handler(request):
|
||||||
|
await request.receive_body()
|
||||||
|
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
# Request Middleware
|
# Request Middleware
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
|
@ -1381,7 +1381,7 @@ class Sanic:
|
||||||
server_settings = {
|
server_settings = {
|
||||||
"protocol": protocol,
|
"protocol": protocol,
|
||||||
"request_class": self.request_class,
|
"request_class": self.request_class,
|
||||||
"is_request_stream": self.is_request_stream,
|
"is_request_stream": True,
|
||||||
"router": self.router,
|
"router": self.router,
|
||||||
"host": host,
|
"host": host,
|
||||||
"port": port,
|
"port": port,
|
||||||
|
|
|
@ -190,7 +190,6 @@ class ASGIApp:
|
||||||
sanic_app: "sanic.app.Sanic"
|
sanic_app: "sanic.app.Sanic"
|
||||||
request: Request
|
request: Request
|
||||||
transport: MockTransport
|
transport: MockTransport
|
||||||
do_stream: bool
|
|
||||||
lifespan: Lifespan
|
lifespan: Lifespan
|
||||||
ws: Optional[WebSocketConnection]
|
ws: Optional[WebSocketConnection]
|
||||||
|
|
||||||
|
@ -213,9 +212,6 @@ class ASGIApp:
|
||||||
for key, value in scope.get("headers", [])
|
for key, value in scope.get("headers", [])
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
instance.do_stream = (
|
|
||||||
True if headers.get("expect") == "100-continue" else False
|
|
||||||
)
|
|
||||||
instance.lifespan = Lifespan(instance)
|
instance.lifespan = Lifespan(instance)
|
||||||
|
|
||||||
if scope["type"] == "lifespan":
|
if scope["type"] == "lifespan":
|
||||||
|
@ -256,15 +252,9 @@ class ASGIApp:
|
||||||
sanic_app,
|
sanic_app,
|
||||||
)
|
)
|
||||||
|
|
||||||
if sanic_app.is_request_stream:
|
instance.request.stream = StreamBuffer(
|
||||||
is_stream_handler = sanic_app.router.is_stream_handler(
|
sanic_app.config.REQUEST_BUFFER_QUEUE_SIZE
|
||||||
instance.request
|
)
|
||||||
)
|
|
||||||
if is_stream_handler:
|
|
||||||
instance.request.stream = StreamBuffer(
|
|
||||||
sanic_app.config.REQUEST_BUFFER_QUEUE_SIZE
|
|
||||||
)
|
|
||||||
instance.do_stream = True
|
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
@ -300,10 +290,7 @@ class ASGIApp:
|
||||||
"""
|
"""
|
||||||
Handle the incoming request.
|
Handle the incoming request.
|
||||||
"""
|
"""
|
||||||
if not self.do_stream:
|
self.sanic_app.loop.create_task(self.stream_body())
|
||||||
self.request.body = await self.read_body()
|
|
||||||
else:
|
|
||||||
self.sanic_app.loop.create_task(self.stream_body())
|
|
||||||
|
|
||||||
handler = self.sanic_app.handle_request
|
handler = self.sanic_app.handle_request
|
||||||
callback = None if self.ws else self.stream_callback
|
callback = None if self.ws else self.stream_callback
|
||||||
|
|
|
@ -116,7 +116,7 @@ class Request:
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
|
|
||||||
# Init but do not inhale
|
# Init but do not inhale
|
||||||
self.body_init()
|
self.body = None
|
||||||
self.ctx = SimpleNamespace()
|
self.ctx = SimpleNamespace()
|
||||||
self.parsed_forwarded = None
|
self.parsed_forwarded = None
|
||||||
self.parsed_json = None
|
self.parsed_json = None
|
||||||
|
@ -159,17 +159,7 @@ class Request:
|
||||||
Custom context is now stored in `request.custom_context.yourkey`"""
|
Custom context is now stored in `request.custom_context.yourkey`"""
|
||||||
setattr(self.ctx, key, value)
|
setattr(self.ctx, key, value)
|
||||||
|
|
||||||
def body_init(self):
|
|
||||||
self.body = []
|
|
||||||
|
|
||||||
def body_push(self, data):
|
|
||||||
self.body.append(data)
|
|
||||||
|
|
||||||
def body_finish(self):
|
|
||||||
self.body = b"".join(self.body)
|
|
||||||
|
|
||||||
async def receive_body(self):
|
async def receive_body(self):
|
||||||
assert self.body == []
|
|
||||||
self.body = b"".join([data async for data in self.stream])
|
self.body = b"".join([data async for data in self.stream])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -328,14 +328,8 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self.expect_handler()
|
self.expect_handler()
|
||||||
|
|
||||||
if self.is_request_stream:
|
if self.is_request_stream:
|
||||||
self._is_stream_handler = self.router.is_stream_handler(
|
self.request.stream = StreamBuffer(self.request_buffer_queue_size)
|
||||||
self.request
|
self.execute_request_handler()
|
||||||
)
|
|
||||||
if self._is_stream_handler:
|
|
||||||
self.request.stream = StreamBuffer(
|
|
||||||
self.request_buffer_queue_size
|
|
||||||
)
|
|
||||||
self.execute_request_handler()
|
|
||||||
|
|
||||||
def expect_handler(self):
|
def expect_handler(self):
|
||||||
"""
|
"""
|
||||||
|
@ -353,21 +347,18 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_body(self, body):
|
def on_body(self, body):
|
||||||
if self.is_request_stream and self._is_stream_handler:
|
# body chunks can be put into asyncio.Queue out of order if
|
||||||
# body chunks can be put into asyncio.Queue out of order if
|
# multiple tasks put concurrently and the queue is full in python
|
||||||
# multiple tasks put concurrently and the queue is full in python
|
# 3.7. so we should not create more than one task putting into the
|
||||||
# 3.7. so we should not create more than one task putting into the
|
# queue simultaneously.
|
||||||
# queue simultaneously.
|
self._body_chunks.append(body)
|
||||||
self._body_chunks.append(body)
|
if (
|
||||||
if (
|
not self._request_stream_task
|
||||||
not self._request_stream_task
|
or self._request_stream_task.done()
|
||||||
or self._request_stream_task.done()
|
):
|
||||||
):
|
self._request_stream_task = self.loop.create_task(
|
||||||
self._request_stream_task = self.loop.create_task(
|
self.stream_append()
|
||||||
self.stream_append()
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
self.request.body_push(body)
|
|
||||||
|
|
||||||
async def body_append(self, body):
|
async def body_append(self, body):
|
||||||
if (
|
if (
|
||||||
|
@ -385,7 +376,7 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
await self.request.stream.put(body)
|
await self.request.stream.put(body)
|
||||||
|
|
||||||
async def stream_append(self):
|
async def stream_append(self):
|
||||||
while self._body_chunks:
|
while self._body_chunks and self.request:
|
||||||
body = self._body_chunks.popleft()
|
body = self._body_chunks.popleft()
|
||||||
if self.request.stream.is_full():
|
if self.request.stream.is_full():
|
||||||
self.transport.pause_reading()
|
self.transport.pause_reading()
|
||||||
|
@ -393,6 +384,7 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self.transport.resume_reading()
|
self.transport.resume_reading()
|
||||||
else:
|
else:
|
||||||
await self.request.stream.put(body)
|
await self.request.stream.put(body)
|
||||||
|
self._body_chunks.clear()
|
||||||
|
|
||||||
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.
|
||||||
|
@ -400,18 +392,15 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
if self._request_timeout_handler:
|
if self._request_timeout_handler:
|
||||||
self._request_timeout_handler.cancel()
|
self._request_timeout_handler.cancel()
|
||||||
self._request_timeout_handler = None
|
self._request_timeout_handler = None
|
||||||
if self.is_request_stream and self._is_stream_handler:
|
|
||||||
self._body_chunks.append(None)
|
self._body_chunks.append(None)
|
||||||
if (
|
if (
|
||||||
not self._request_stream_task
|
not self._request_stream_task
|
||||||
or self._request_stream_task.done()
|
or self._request_stream_task.done()
|
||||||
):
|
):
|
||||||
self._request_stream_task = self.loop.create_task(
|
self._request_stream_task = self.loop.create_task(
|
||||||
self.stream_append()
|
self.stream_append()
|
||||||
)
|
)
|
||||||
return
|
|
||||||
self.request.body_finish()
|
|
||||||
self.execute_request_handler()
|
|
||||||
|
|
||||||
def execute_request_handler(self):
|
def execute_request_handler(self):
|
||||||
"""
|
"""
|
||||||
|
@ -639,7 +628,6 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self._request_handler_task = None
|
self._request_handler_task = None
|
||||||
self._request_stream_task = None
|
self._request_stream_task = None
|
||||||
self._total_request_size = 0
|
self._total_request_size = 0
|
||||||
self._is_stream_handler = False
|
|
||||||
|
|
||||||
def close_if_idle(self):
|
def close_if_idle(self):
|
||||||
"""Close the connection if a request is not being sent or received
|
"""Close the connection if a request is not being sent or received
|
||||||
|
|
|
@ -71,7 +71,6 @@ def test_bp(app):
|
||||||
|
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
request, response = app.test_client.get("/")
|
request, response = app.test_client.get("/")
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
assert response.text == "Hello"
|
assert response.text == "Hello"
|
||||||
|
|
||||||
|
@ -383,48 +382,38 @@ def test_bp_shorthand(app):
|
||||||
|
|
||||||
@blueprint.get("/get")
|
@blueprint.get("/get")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.put("/put")
|
@blueprint.put("/put")
|
||||||
def put_handler(request):
|
def put_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.post("/post")
|
@blueprint.post("/post")
|
||||||
def post_handler(request):
|
def post_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.head("/head")
|
@blueprint.head("/head")
|
||||||
def head_handler(request):
|
def head_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.options("/options")
|
@blueprint.options("/options")
|
||||||
def options_handler(request):
|
def options_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.patch("/patch")
|
@blueprint.patch("/patch")
|
||||||
def patch_handler(request):
|
def patch_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.delete("/delete")
|
@blueprint.delete("/delete")
|
||||||
def delete_handler(request):
|
def delete_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@blueprint.websocket("/ws/", strict_slashes=True)
|
@blueprint.websocket("/ws/", strict_slashes=True)
|
||||||
async def websocket_handler(request, ws):
|
async def websocket_handler(request, ws):
|
||||||
assert request.stream is None
|
|
||||||
ev.set()
|
ev.set()
|
||||||
|
|
||||||
app.blueprint(blueprint)
|
app.blueprint(blueprint)
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/get")
|
request, response = app.test_client.get("/get")
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ def test_custom_request():
|
||||||
"/post", data=json_dumps(payload), headers=headers
|
"/post", data=json_dumps(payload), headers=headers
|
||||||
)
|
)
|
||||||
|
|
||||||
assert isinstance(request.body_buffer, BytesIO)
|
|
||||||
assert request.body_buffer.closed
|
|
||||||
assert request.body == b'{"test":"OK"}'
|
assert request.body == b'{"test":"OK"}'
|
||||||
assert request.json.get("test") == "OK"
|
assert request.json.get("test") == "OK"
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
@ -46,8 +44,6 @@ def test_custom_request():
|
||||||
|
|
||||||
request, response = app.test_client.get("/get")
|
request, response = app.test_client.get("/get")
|
||||||
|
|
||||||
assert isinstance(request.body_buffer, BytesIO)
|
|
||||||
assert request.body_buffer.closed
|
|
||||||
assert request.body == b""
|
assert request.body == b""
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
|
@ -85,5 +85,4 @@ def test_pickle_app_with_bp(app, protocol):
|
||||||
up_p_app = pickle.loads(p_app)
|
up_p_app = pickle.loads(p_app)
|
||||||
assert up_p_app
|
assert up_p_app
|
||||||
request, response = up_p_app.test_client.get("/")
|
request, response = up_p_app.test_client.get("/")
|
||||||
assert up_p_app.is_request_stream is False
|
|
||||||
assert response.text == "Hello"
|
assert response.text == "Hello"
|
||||||
|
|
|
@ -107,10 +107,8 @@ def test_shorthand_named_routes_post(app):
|
||||||
def test_shorthand_named_routes_put(app):
|
def test_shorthand_named_routes_put(app):
|
||||||
@app.put("/put", name="route_put")
|
@app.put("/put", name="route_put")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
assert app.router.routes_all["/put"].name == "route_put"
|
assert app.router.routes_all["/put"].name == "route_put"
|
||||||
assert app.url_for("route_put") == "/put"
|
assert app.url_for("route_put") == "/put"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
|
@ -120,10 +118,8 @@ def test_shorthand_named_routes_put(app):
|
||||||
def test_shorthand_named_routes_delete(app):
|
def test_shorthand_named_routes_delete(app):
|
||||||
@app.delete("/delete", name="route_delete")
|
@app.delete("/delete", name="route_delete")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
assert app.router.routes_all["/delete"].name == "route_delete"
|
assert app.router.routes_all["/delete"].name == "route_delete"
|
||||||
assert app.url_for("route_delete") == "/delete"
|
assert app.url_for("route_delete") == "/delete"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
|
@ -133,10 +129,8 @@ def test_shorthand_named_routes_delete(app):
|
||||||
def test_shorthand_named_routes_patch(app):
|
def test_shorthand_named_routes_patch(app):
|
||||||
@app.patch("/patch", name="route_patch")
|
@app.patch("/patch", name="route_patch")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
assert app.router.routes_all["/patch"].name == "route_patch"
|
assert app.router.routes_all["/patch"].name == "route_patch"
|
||||||
assert app.url_for("route_patch") == "/patch"
|
assert app.url_for("route_patch") == "/patch"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
|
@ -146,10 +140,8 @@ def test_shorthand_named_routes_patch(app):
|
||||||
def test_shorthand_named_routes_head(app):
|
def test_shorthand_named_routes_head(app):
|
||||||
@app.head("/head", name="route_head")
|
@app.head("/head", name="route_head")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
assert app.router.routes_all["/head"].name == "route_head"
|
assert app.router.routes_all["/head"].name == "route_head"
|
||||||
assert app.url_for("route_head") == "/head"
|
assert app.url_for("route_head") == "/head"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
|
@ -159,10 +151,8 @@ def test_shorthand_named_routes_head(app):
|
||||||
def test_shorthand_named_routes_options(app):
|
def test_shorthand_named_routes_options(app):
|
||||||
@app.options("/options", name="route_options")
|
@app.options("/options", name="route_options")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
assert app.router.routes_all["/options"].name == "route_options"
|
assert app.router.routes_all["/options"].name == "route_options"
|
||||||
assert app.url_for("route_options") == "/options"
|
assert app.url_for("route_options") == "/options"
|
||||||
with pytest.raises(URLBuildError):
|
with pytest.raises(URLBuildError):
|
||||||
|
|
|
@ -12,28 +12,23 @@ data = "abc" * 10000000
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_method_view(app):
|
def test_request_stream_method_view(app):
|
||||||
"""for self.is_request_stream = True"""
|
|
||||||
|
|
||||||
class SimpleView(HTTPMethodView):
|
class SimpleView(HTTPMethodView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@stream_decorator
|
@stream_decorator
|
||||||
async def post(self, request):
|
async def post(self, request):
|
||||||
assert isinstance(request.stream, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ""
|
result = b""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode("utf-8")
|
result += body
|
||||||
return text(result)
|
return text(result.decode())
|
||||||
|
|
||||||
app.add_route(SimpleView.as_view(), "/method_view")
|
app.add_route(SimpleView.as_view(), "/method_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/method_view")
|
request, response = app.test_client.get("/method_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
@ -65,8 +60,6 @@ def test_request_stream_100_continue(app, headers, expect_raise_exception):
|
||||||
|
|
||||||
app.add_route(SimpleView.as_view(), "/method_view")
|
app.add_route(SimpleView.as_view(), "/method_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
if not expect_raise_exception:
|
if not expect_raise_exception:
|
||||||
request, response = app.test_client.post(
|
request, response = app.test_client.post(
|
||||||
"/method_view", data=data, headers={"EXPECT": "100-continue"}
|
"/method_view", data=data, headers={"EXPECT": "100-continue"}
|
||||||
|
@ -84,31 +77,24 @@ def test_request_stream_100_continue(app, headers, expect_raise_exception):
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_app(app):
|
def test_request_stream_app(app):
|
||||||
"""for self.is_request_stream = True and decorators"""
|
|
||||||
|
|
||||||
@app.get("/get")
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("GET")
|
return text("GET")
|
||||||
|
|
||||||
@app.head("/head")
|
@app.head("/head")
|
||||||
async def head(request):
|
async def head(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("HEAD")
|
return text("HEAD")
|
||||||
|
|
||||||
@app.delete("/delete")
|
@app.delete("/delete")
|
||||||
async def delete(request):
|
async def delete(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("DELETE")
|
return text("DELETE")
|
||||||
|
|
||||||
@app.options("/options")
|
@app.options("/options")
|
||||||
async def options(request):
|
async def options(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OPTIONS")
|
return text("OPTIONS")
|
||||||
|
|
||||||
@app.post("/_post/<id>")
|
@app.post("/_post/<id>")
|
||||||
async def _post(request, id):
|
async def _post(request, id):
|
||||||
assert request.stream is None
|
|
||||||
return text("_POST")
|
return text("_POST")
|
||||||
|
|
||||||
@app.post("/post/<id>", stream=True)
|
@app.post("/post/<id>", stream=True)
|
||||||
|
@ -124,7 +110,6 @@ def test_request_stream_app(app):
|
||||||
|
|
||||||
@app.put("/_put")
|
@app.put("/_put")
|
||||||
async def _put(request):
|
async def _put(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("_PUT")
|
return text("_PUT")
|
||||||
|
|
||||||
@app.put("/put", stream=True)
|
@app.put("/put", stream=True)
|
||||||
|
@ -140,7 +125,6 @@ def test_request_stream_app(app):
|
||||||
|
|
||||||
@app.patch("/_patch")
|
@app.patch("/_patch")
|
||||||
async def _patch(request):
|
async def _patch(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("_PATCH")
|
return text("_PATCH")
|
||||||
|
|
||||||
@app.patch("/patch", stream=True)
|
@app.patch("/patch", stream=True)
|
||||||
|
@ -154,8 +138,6 @@ def test_request_stream_app(app):
|
||||||
result += body.decode("utf-8")
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/get")
|
request, response = app.test_client.get("/get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "GET"
|
assert response.text == "GET"
|
||||||
|
@ -199,31 +181,24 @@ def test_request_stream_app(app):
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_request_stream_app_asgi(app):
|
async def test_request_stream_app_asgi(app):
|
||||||
"""for self.is_request_stream = True and decorators"""
|
|
||||||
|
|
||||||
@app.get("/get")
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("GET")
|
return text("GET")
|
||||||
|
|
||||||
@app.head("/head")
|
@app.head("/head")
|
||||||
async def head(request):
|
async def head(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("HEAD")
|
return text("HEAD")
|
||||||
|
|
||||||
@app.delete("/delete")
|
@app.delete("/delete")
|
||||||
async def delete(request):
|
async def delete(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("DELETE")
|
return text("DELETE")
|
||||||
|
|
||||||
@app.options("/options")
|
@app.options("/options")
|
||||||
async def options(request):
|
async def options(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OPTIONS")
|
return text("OPTIONS")
|
||||||
|
|
||||||
@app.post("/_post/<id>")
|
@app.post("/_post/<id>")
|
||||||
async def _post(request, id):
|
async def _post(request, id):
|
||||||
assert request.stream is None
|
|
||||||
return text("_POST")
|
return text("_POST")
|
||||||
|
|
||||||
@app.post("/post/<id>", stream=True)
|
@app.post("/post/<id>", stream=True)
|
||||||
|
@ -239,7 +214,6 @@ async def test_request_stream_app_asgi(app):
|
||||||
|
|
||||||
@app.put("/_put")
|
@app.put("/_put")
|
||||||
async def _put(request):
|
async def _put(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("_PUT")
|
return text("_PUT")
|
||||||
|
|
||||||
@app.put("/put", stream=True)
|
@app.put("/put", stream=True)
|
||||||
|
@ -255,7 +229,6 @@ async def test_request_stream_app_asgi(app):
|
||||||
|
|
||||||
@app.patch("/_patch")
|
@app.patch("/_patch")
|
||||||
async def _patch(request):
|
async def _patch(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("_PATCH")
|
return text("_PATCH")
|
||||||
|
|
||||||
@app.patch("/patch", stream=True)
|
@app.patch("/patch", stream=True)
|
||||||
|
@ -269,8 +242,6 @@ async def test_request_stream_app_asgi(app):
|
||||||
result += body.decode("utf-8")
|
result += body.decode("utf-8")
|
||||||
return text(result)
|
return text(result)
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
request, response = await app.asgi_client.get("/get")
|
request, response = await app.asgi_client.get("/get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "GET"
|
assert response.text == "GET"
|
||||||
|
@ -318,13 +289,13 @@ 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, StreamBuffer)
|
assert isinstance(request.stream, StreamBuffer)
|
||||||
result = ""
|
result = b""
|
||||||
while True:
|
while True:
|
||||||
body = await request.stream.read()
|
body = await request.stream.read()
|
||||||
if body is None:
|
if body is None:
|
||||||
break
|
break
|
||||||
result += body.decode("utf-8")
|
result += body
|
||||||
return text(result)
|
return text(result.decode())
|
||||||
|
|
||||||
# 404
|
# 404
|
||||||
request, response = app.test_client.post("/in_valid_post", data=data)
|
request, response = app.test_client.post("/in_valid_post", data=data)
|
||||||
|
@ -338,32 +309,26 @@ def test_request_stream_handle_exception(app):
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_blueprint(app):
|
def test_request_stream_blueprint(app):
|
||||||
"""for self.is_request_stream = True"""
|
|
||||||
bp = Blueprint("test_blueprint_request_stream_blueprint")
|
bp = Blueprint("test_blueprint_request_stream_blueprint")
|
||||||
|
|
||||||
@app.get("/get")
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("GET")
|
return text("GET")
|
||||||
|
|
||||||
@bp.head("/head")
|
@bp.head("/head")
|
||||||
async def head(request):
|
async def head(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("HEAD")
|
return text("HEAD")
|
||||||
|
|
||||||
@bp.delete("/delete")
|
@bp.delete("/delete")
|
||||||
async def delete(request):
|
async def delete(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("DELETE")
|
return text("DELETE")
|
||||||
|
|
||||||
@bp.options("/options")
|
@bp.options("/options")
|
||||||
async def options(request):
|
async def options(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OPTIONS")
|
return text("OPTIONS")
|
||||||
|
|
||||||
@bp.post("/_post/<id>")
|
@bp.post("/_post/<id>")
|
||||||
async def _post(request, id):
|
async def _post(request, id):
|
||||||
assert request.stream is None
|
|
||||||
return text("_POST")
|
return text("_POST")
|
||||||
|
|
||||||
@bp.post("/post/<id>", stream=True)
|
@bp.post("/post/<id>", stream=True)
|
||||||
|
@ -379,7 +344,6 @@ def test_request_stream_blueprint(app):
|
||||||
|
|
||||||
@bp.put("/_put")
|
@bp.put("/_put")
|
||||||
async def _put(request):
|
async def _put(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("_PUT")
|
return text("_PUT")
|
||||||
|
|
||||||
@bp.put("/put", stream=True)
|
@bp.put("/put", stream=True)
|
||||||
|
@ -395,7 +359,6 @@ def test_request_stream_blueprint(app):
|
||||||
|
|
||||||
@bp.patch("/_patch")
|
@bp.patch("/_patch")
|
||||||
async def _patch(request):
|
async def _patch(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("_PATCH")
|
return text("_PATCH")
|
||||||
|
|
||||||
@bp.patch("/patch", stream=True)
|
@bp.patch("/patch", stream=True)
|
||||||
|
@ -424,8 +387,6 @@ def test_request_stream_blueprint(app):
|
||||||
)
|
)
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/get")
|
request, response = app.test_client.get("/get")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "GET"
|
assert response.text == "GET"
|
||||||
|
@ -472,10 +433,7 @@ def test_request_stream_blueprint(app):
|
||||||
|
|
||||||
|
|
||||||
def test_request_stream_composition_view(app):
|
def test_request_stream_composition_view(app):
|
||||||
"""for self.is_request_stream = True"""
|
|
||||||
|
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
|
@ -493,8 +451,6 @@ def test_request_stream_composition_view(app):
|
||||||
view.add(["POST"], post_handler, stream=True)
|
view.add(["POST"], post_handler, stream=True)
|
||||||
app.add_route(view, "/composition_view")
|
app.add_route(view, "/composition_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/composition_view")
|
request, response = app.test_client.get("/composition_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
@ -510,7 +466,6 @@ def test_request_stream(app):
|
||||||
|
|
||||||
class SimpleView(HTTPMethodView):
|
class SimpleView(HTTPMethodView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@stream_decorator
|
@stream_decorator
|
||||||
|
@ -537,7 +492,6 @@ def test_request_stream(app):
|
||||||
|
|
||||||
@app.get("/get")
|
@app.get("/get")
|
||||||
async def get(request):
|
async def get(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@bp.post("/bp_stream", stream=True)
|
@bp.post("/bp_stream", stream=True)
|
||||||
|
@ -553,11 +507,9 @@ def test_request_stream(app):
|
||||||
|
|
||||||
@bp.get("/bp_get")
|
@bp.get("/bp_get")
|
||||||
async def bp_get(request):
|
async def bp_get(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
def get_handler(request):
|
def get_handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
async def post_handler(request):
|
async def post_handler(request):
|
||||||
|
@ -580,8 +532,6 @@ def test_request_stream(app):
|
||||||
|
|
||||||
app.add_route(view, "/composition_view")
|
app.add_route(view, "/composition_view")
|
||||||
|
|
||||||
assert app.is_request_stream is True
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/method_view")
|
request, response = app.test_client.get("/method_view")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
|
|
@ -66,16 +66,12 @@ def test_shorthand_routes_multiple(app):
|
||||||
def test_route_strict_slash(app):
|
def test_route_strict_slash(app):
|
||||||
@app.get("/get", strict_slashes=True)
|
@app.get("/get", strict_slashes=True)
|
||||||
def handler1(request):
|
def handler1(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
@app.post("/post/", strict_slashes=True)
|
@app.post("/post/", strict_slashes=True)
|
||||||
def handler2(request):
|
def handler2(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.get("/get")
|
request, response = app.test_client.get("/get")
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
@ -214,11 +210,8 @@ def test_shorthand_routes_post(app):
|
||||||
def test_shorthand_routes_put(app):
|
def test_shorthand_routes_put(app):
|
||||||
@app.put("/put")
|
@app.put("/put")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.put("/put")
|
request, response = app.test_client.put("/put")
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
@ -229,11 +222,8 @@ def test_shorthand_routes_put(app):
|
||||||
def test_shorthand_routes_delete(app):
|
def test_shorthand_routes_delete(app):
|
||||||
@app.delete("/delete")
|
@app.delete("/delete")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.delete("/delete")
|
request, response = app.test_client.delete("/delete")
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
@ -244,11 +234,8 @@ def test_shorthand_routes_delete(app):
|
||||||
def test_shorthand_routes_patch(app):
|
def test_shorthand_routes_patch(app):
|
||||||
@app.patch("/patch")
|
@app.patch("/patch")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.patch("/patch")
|
request, response = app.test_client.patch("/patch")
|
||||||
assert response.text == "OK"
|
assert response.text == "OK"
|
||||||
|
|
||||||
|
@ -259,11 +246,8 @@ def test_shorthand_routes_patch(app):
|
||||||
def test_shorthand_routes_head(app):
|
def test_shorthand_routes_head(app):
|
||||||
@app.head("/head")
|
@app.head("/head")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.head("/head")
|
request, response = app.test_client.head("/head")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
@ -274,11 +258,8 @@ def test_shorthand_routes_head(app):
|
||||||
def test_shorthand_routes_options(app):
|
def test_shorthand_routes_options(app):
|
||||||
@app.options("/options")
|
@app.options("/options")
|
||||||
def handler(request):
|
def handler(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("OK")
|
return text("OK")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = app.test_client.options("/options")
|
request, response = app.test_client.options("/options")
|
||||||
assert response.status == 200
|
assert response.status == 200
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ from sanic.views import CompositionView, HTTPMethodView
|
||||||
def test_methods(app, method):
|
def test_methods(app, method):
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
async def get(self, request):
|
async def get(self, request):
|
||||||
assert request.stream is None
|
|
||||||
return text("", headers={"method": "GET"})
|
return text("", headers={"method": "GET"})
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
|
@ -34,7 +33,6 @@ def test_methods(app, method):
|
||||||
return text("", headers={"method": "DELETE"})
|
return text("", headers={"method": "DELETE"})
|
||||||
|
|
||||||
app.add_route(DummyView.as_view(), "/")
|
app.add_route(DummyView.as_view(), "/")
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
request, response = getattr(app.test_client, method.lower())("/")
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
assert response.headers["method"] == method
|
assert response.headers["method"] == method
|
||||||
|
@ -69,7 +67,6 @@ def test_with_bp(app):
|
||||||
|
|
||||||
class DummyView(HTTPMethodView):
|
class DummyView(HTTPMethodView):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
assert request.stream is None
|
|
||||||
return text("I am get method")
|
return text("I am get method")
|
||||||
|
|
||||||
bp.add_route(DummyView.as_view(), "/")
|
bp.add_route(DummyView.as_view(), "/")
|
||||||
|
@ -77,7 +74,6 @@ def test_with_bp(app):
|
||||||
app.blueprint(bp)
|
app.blueprint(bp)
|
||||||
request, response = app.test_client.get("/")
|
request, response = app.test_client.get("/")
|
||||||
|
|
||||||
assert app.is_request_stream is False
|
|
||||||
assert response.text == "I am get method"
|
assert response.text == "I am get method"
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,14 +207,12 @@ def test_composition_view_runs_methods_as_expected(app, method):
|
||||||
view = CompositionView()
|
view = CompositionView()
|
||||||
|
|
||||||
def first(request):
|
def first(request):
|
||||||
assert request.stream is None
|
|
||||||
return text("first method")
|
return text("first method")
|
||||||
|
|
||||||
view.add(["GET", "POST", "PUT"], first)
|
view.add(["GET", "POST", "PUT"], first)
|
||||||
view.add(["DELETE", "PATCH"], lambda x: text("second method"))
|
view.add(["DELETE", "PATCH"], lambda x: text("second method"))
|
||||||
|
|
||||||
app.add_route(view, "/")
|
app.add_route(view, "/")
|
||||||
assert app.is_request_stream is False
|
|
||||||
|
|
||||||
if method in ["GET", "POST", "PUT"]:
|
if method in ["GET", "POST", "PUT"]:
|
||||||
request, response = getattr(app.test_client, method.lower())("/")
|
request, response = getattr(app.test_client, method.lower())("/")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user