Originally posted by MarkLux August 9, 2024
Background
Phenomenon
# http2.py, class AsyncHTTP2Connection
# ...
async def _receive_stream_event(
self, request: Request, stream_id: int
) -> typing.Union[
h2.events.ResponseReceived, h2.events.DataReceived, h2.events.StreamEnded
]:
while not self._events.get(stream_id):
# REST STREAM ARE BLOCKED HERE
# for each loop, the _receive_events give an events that belongs to other stream (those we closed, but server didn't know, keep sending)
await self._receive_events(request, stream_id)
event = self._events[stream_id].pop(0)
if isinstance(event, h2.events.StreamReset):
raise RemoteProtocolError(event)
return event
we made some experiments and the following logs were observed
Solution
reset the stream when client cancelled the stream, here is a demo (have made experiments to prove it works)
# http2.py, class AsyncHTTP2Connection
async def _response_closed(self, stream_id: int) -> None:
await self._max_streams_semaphore.release()
del self._events[stream_id]
# ADD
stream = self._h2_state._get_stream_by_id(stream_id=stream_id)
if stream and not stream.closed:
# send a RstStream with Cancel Code
self._h2_state.reset_stream(stream_id=stream_id, error_code=8)
# ADD END
async with self._state_lock:
if self._connection_terminated and not self._events:
await self.aclose()
We referred some h2 libraries of other language, and found that the 'client stream reset when cancelled' behavior were both implemented.
e.g.1: go net http2 library
e.g.2: rust h2 library
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too