diff --git a/tests/protocols/test_http.py b/tests/protocols/test_http.py index 45ccc1d23..db196d99c 100644 --- a/tests/protocols/test_http.py +++ b/tests/protocols/test_http.py @@ -61,6 +61,20 @@ CONNECTION_CLOSE_REQUEST = b"\r\n".join([b"GET / HTTP/1.1", b"Host: example.org", b"Connection: close", b"", b""]) +REQUEST_AFTER_CONNECTION_CLOSE = b"\r\n".join( + [ + b"GET / HTTP/1.1", + b"Host: example.org", + b"Connection: close", + b"", + b"", + b"GET / HTTP/1.1", + b"Host: example.org", + b"", + b"", + ] +) + LARGE_POST_REQUEST = b"\r\n".join( [ b"POST / HTTP/1.1", @@ -983,6 +997,20 @@ async def test_return_close_header(http_protocol_cls: HTTPProtocol): assert b"connection: close" in protocol.transport.buffer.lower() +async def test_close_connection_with_multiple_requests(http_protocol_cls: HTTPProtocol): + app = Response("Hello, world", media_type="text/plain") + + protocol = get_connected_protocol(app, http_protocol_cls) + protocol.data_received(REQUEST_AFTER_CONNECTION_CLOSE) + await protocol.loop.run_one() + assert b"HTTP/1.1 200 OK" in protocol.transport.buffer + assert b"content-type: text/plain" in protocol.transport.buffer + assert b"content-length: 12" in protocol.transport.buffer + # NOTE: We need to use `.lower()` because H11 implementation doesn't allow Uvicorn + # to lowercase them. See: https://github.com/python-hyper/h11/issues/156 + assert b"connection: close" in protocol.transport.buffer.lower() + + async def test_iterator_headers(http_protocol_cls: HTTPProtocol): async def app(scope: Scope, receive: ASGIReceiveCallable, send: ASGISendCallable): headers = iter([(b"x-test-header", b"test value")]) diff --git a/uvicorn/protocols/http/h11_impl.py b/uvicorn/protocols/http/h11_impl.py index 9d2a2dabd..04d51dfdb 100644 --- a/uvicorn/protocols/http/h11_impl.py +++ b/uvicorn/protocols/http/h11_impl.py @@ -259,6 +259,8 @@ def handle_events(self) -> None: self.transport.resume_reading() self.conn.start_next_cycle() continue + if self.conn.their_state == h11.MUST_CLOSE: + break self.cycle.more_body = False self.cycle.message_event.set()