Skip to content

Commit 5997901

Browse files
committed
fix(h2_connection_reset): add stream reset when client cancel the request
1 parent 7d87c9d commit 5997901

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

httpcore/_async/http2.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import asyncio
12
import enum
23
import logging
34
import time
@@ -401,6 +402,9 @@ async def _receive_remote_settings_change(self, event: h2.events.Event) -> None:
401402
await self._max_streams_semaphore.acquire()
402403
self._max_streams -= 1
403404

405+
async def _reset_steam(self, stream_id: int, error_code: int) -> None:
406+
self._h2_state.reset_stream(stream_id=stream_id, error_code=error_code)
407+
404408
async def _response_closed(self, stream_id: int) -> None:
405409
await self._max_streams_semaphore.release()
406410
del self._events[stream_id]
@@ -578,12 +582,18 @@ async def __aiter__(self) -> typing.AsyncIterator[bytes]:
578582
# we want to close the response (and possibly the connection)
579583
# before raising that exception.
580584
with AsyncShieldCancellation():
581-
await self.aclose()
585+
# close the stream with cancel
586+
await self.aclose(cancel_stream=isinstance(exc, asyncio.exceptions.CancelledError))
582587
raise exc
583588

584-
async def aclose(self) -> None:
589+
async def aclose(self, cancel_stream: bool = False) -> None:
585590
if not self._closed:
586591
self._closed = True
587592
kwargs = {"stream_id": self._stream_id}
588593
async with Trace("response_closed", logger, self._request, kwargs):
594+
if cancel_stream:
595+
await self._connection._reset_steam(
596+
stream_id=self._stream_id,
597+
error_code=h2.settings.ErrorCodes.CANCEL,
598+
)
589599
await self._connection._response_closed(stream_id=self._stream_id)

httpcore/_sync/http2.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,9 @@ def _receive_remote_settings_change(self, event: h2.events.Event) -> None:
401401
self._max_streams_semaphore.acquire()
402402
self._max_streams -= 1
403403

404+
def _reset_steam(self, stream_id: int, error_code: int) -> None:
405+
self._h2_state.reset_stream(stream_id=stream_id, error_code=error_code)
406+
404407
def _response_closed(self, stream_id: int) -> None:
405408
self._max_streams_semaphore.release()
406409
del self._events[stream_id]
@@ -578,12 +581,18 @@ def __iter__(self) -> typing.Iterator[bytes]:
578581
# we want to close the response (and possibly the connection)
579582
# before raising that exception.
580583
with ShieldCancellation():
581-
self.close()
584+
# close the stream with cancel
585+
self.close(cancel_stream=True)
582586
raise exc
583587

584-
def close(self) -> None:
588+
def close(self, cancel_stream: bool = False) -> None:
585589
if not self._closed:
586590
self._closed = True
587591
kwargs = {"stream_id": self._stream_id}
588592
with Trace("response_closed", logger, self._request, kwargs):
593+
if cancel_stream:
594+
self._connection._reset_steam(
595+
stream_id=self._stream_id,
596+
error_code=h2.settings.ErrorCodes.CANCEL,
597+
)
589598
self._connection._response_closed(stream_id=self._stream_id)

0 commit comments

Comments
 (0)