Skip to content

Commit

Permalink
close request connection if h11 sets client state as MUST_CLOSE (#2375)
Browse files Browse the repository at this point in the history
* close request connection if h11 sets client state as MUST_CLOSE

* fixed data assignment for ReceiveBuffer and added test case

* improved close header test case

* fixed linting for close header related test case

* Fixed handling connection close header. Added separate test case

---------

Co-authored-by: Marcelo Trylesinski <[email protected]>
  • Loading branch information
theyashl and Kludex committed Jul 31, 2024
1 parent d277c25 commit ce999aa
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 0 deletions.
28 changes: 28 additions & 0 deletions tests/protocols/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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")])
Expand Down
2 changes: 2 additions & 0 deletions uvicorn/protocols/http/h11_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down

0 comments on commit ce999aa

Please sign in to comment.