Skip to content

Commit a3615da

Browse files
authored
fix: handle http2 goaway race conditions (#4)
1 parent e401864 commit a3615da

File tree

2 files changed

+10
-10
lines changed

2 files changed

+10
-10
lines changed

tests/_async/test_http2_goaway.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ async def test_http2_server_disconnect_with_h2_closed_state():
891891
# Create a mock stream that sets state to CLOSED BEFORE returning empty data
892892
# This simulates the race condition accurately
893893
class MockStreamWithClosedStateOnDisconnect(httpcore.AsyncMockStream):
894-
def __init__(self, conn_ref: list) -> None:
894+
def __init__(self, conn_ref: list[httpcore.AsyncHTTP2Connection]) -> None:
895895
self._conn_ref = conn_ref
896896
self._read_count = 0
897897
super().__init__([hyperframe.frame.SettingsFrame().serialize()], http2=True)
@@ -900,7 +900,7 @@ async def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
900900
self._read_count += 1
901901
if self._read_count == 1:
902902
# First read returns settings
903-
return hyperframe.frame.SettingsFrame().serialize()
903+
return bytes(hyperframe.frame.SettingsFrame().serialize())
904904
# Before returning empty (disconnect), set h2 state to CLOSED
905905
# This simulates h2 having processed GOAWAY internally
906906
if self._conn_ref and self._conn_ref[0]:
@@ -910,7 +910,7 @@ async def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
910910
self._conn_ref[0]._connection_terminated = None
911911
return b"" # Server disconnect
912912

913-
conn_ref: list = []
913+
conn_ref: list[httpcore.AsyncHTTP2Connection] = []
914914
stream = MockStreamWithClosedStateOnDisconnect(conn_ref)
915915

916916
async with httpcore.AsyncHTTP2Connection(
@@ -958,7 +958,7 @@ async def test_http2_protocol_error_with_h2_closed_state():
958958
# Create a mock stream that sets state to CLOSED during write
959959
# This causes h2 to raise ProtocolError when trying to read the next frame
960960
class MockStreamWithClosedOnWrite(httpcore.AsyncMockStream):
961-
def __init__(self, conn_ref: list) -> None:
961+
def __init__(self, conn_ref: list[httpcore.AsyncHTTP2Connection]) -> None:
962962
self._conn_ref = conn_ref
963963
self._write_count = 0
964964
super().__init__([hyperframe.frame.SettingsFrame().serialize()], http2=True)
@@ -973,7 +973,7 @@ async def write(self, data: bytes, timeout: float | None = None) -> None:
973973
]._h2_state.state_machine.state = h2.connection.ConnectionState.CLOSED
974974
self._conn_ref[0]._connection_terminated = None
975975

976-
conn_ref: list = []
976+
conn_ref: list[httpcore.AsyncHTTP2Connection] = []
977977
stream = MockStreamWithClosedOnWrite(conn_ref)
978978

979979
async with httpcore.AsyncHTTP2Connection(

tests/_sync/test_http2_goaway.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ def test_http2_server_disconnect_with_h2_closed_state():
891891
# Create a mock stream that sets state to CLOSED BEFORE returning empty data
892892
# This simulates the race condition accurately
893893
class MockStreamWithClosedStateOnDisconnect(httpcore.MockStream):
894-
def __init__(self, conn_ref: list) -> None:
894+
def __init__(self, conn_ref: list[httpcore.HTTP2Connection]) -> None:
895895
self._conn_ref = conn_ref
896896
self._read_count = 0
897897
super().__init__([hyperframe.frame.SettingsFrame().serialize()], http2=True)
@@ -900,7 +900,7 @@ def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
900900
self._read_count += 1
901901
if self._read_count == 1:
902902
# First read returns settings
903-
return hyperframe.frame.SettingsFrame().serialize()
903+
return bytes(hyperframe.frame.SettingsFrame().serialize())
904904
# Before returning empty (disconnect), set h2 state to CLOSED
905905
# This simulates h2 having processed GOAWAY internally
906906
if self._conn_ref and self._conn_ref[0]:
@@ -910,7 +910,7 @@ def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
910910
self._conn_ref[0]._connection_terminated = None
911911
return b"" # Server disconnect
912912

913-
conn_ref: list = []
913+
conn_ref: list[httpcore.HTTP2Connection] = []
914914
stream = MockStreamWithClosedStateOnDisconnect(conn_ref)
915915

916916
with httpcore.HTTP2Connection(
@@ -958,7 +958,7 @@ def test_http2_protocol_error_with_h2_closed_state():
958958
# Create a mock stream that sets state to CLOSED during write
959959
# This causes h2 to raise ProtocolError when trying to read the next frame
960960
class MockStreamWithClosedOnWrite(httpcore.MockStream):
961-
def __init__(self, conn_ref: list) -> None:
961+
def __init__(self, conn_ref: list[httpcore.HTTP2Connection]) -> None:
962962
self._conn_ref = conn_ref
963963
self._write_count = 0
964964
super().__init__([hyperframe.frame.SettingsFrame().serialize()], http2=True)
@@ -973,7 +973,7 @@ def write(self, data: bytes, timeout: float | None = None) -> None:
973973
]._h2_state.state_machine.state = h2.connection.ConnectionState.CLOSED
974974
self._conn_ref[0]._connection_terminated = None
975975

976-
conn_ref: list = []
976+
conn_ref: list[httpcore.HTTP2Connection] = []
977977
stream = MockStreamWithClosedOnWrite(conn_ref)
978978

979979
with httpcore.HTTP2Connection(

0 commit comments

Comments
 (0)