asgi: Send http.disconnect message on receive() after response complete (#909)

Co-authored-by: Florimond Manca <florimond.manca@gmail.com>
This commit is contained in:
Jamie Hewland 2020-05-01 11:51:35 +02:00 committed by GitHub
parent bed3d8bd38
commit 8710079d5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 0 deletions

View File

@ -85,6 +85,11 @@ class ASGIDispatch(httpcore.AsyncHTTPTransport):
request_body_chunks = stream.__aiter__()
async def receive() -> dict:
nonlocal response_complete
if response_complete:
return {"type": "http.disconnect"}
try:
body = await request_body_chunks.__anext__()
except StopAsyncIteration:

View File

@ -67,3 +67,36 @@ async def test_asgi_exc_after_response():
client = httpx.AsyncClient(app=raise_exc_after_response)
with pytest.raises(ValueError):
await client.get("http://www.example.org/")
@pytest.mark.asyncio
async def test_asgi_disconnect_after_response_complete():
disconnect = False
async def read_body(scope, receive, send):
nonlocal disconnect
status = 200
headers = [(b"content-type", "text/plain")]
await send(
{"type": "http.response.start", "status": status, "headers": headers}
)
more_body = True
while more_body:
message = await receive()
more_body = message.get("more_body", False)
await send({"type": "http.response.body", "body": b"", "more_body": False})
# The ASGI spec says of the Disconnect message:
# "Sent to the application when a HTTP connection is closed or if receive is
# called after a response has been sent."
# So if receive() is called again, the disconnect message should be received
message = await receive()
disconnect = message.get("type") == "http.disconnect"
client = httpx.AsyncClient(app=read_body)
response = await client.post("http://www.example.org/", data=b"example")
assert response.status_code == 200
assert disconnect