Skip to content

Commit 2c2ad99

Browse files
Reject non-integer transport response status codes
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 0e211cc commit 2c2ad99

3 files changed

Lines changed: 55 additions & 6 deletions

File tree

hyperbrowser/transport/async_transport.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ def __init__(self, api_key: str, headers: Optional[Mapping[str, str]] = None):
4343
def _normalize_response_status_code(self, response: httpx.Response) -> int:
4444
try:
4545
status_code = response.status_code
46-
if isinstance(status_code, bool):
47-
raise TypeError("boolean status code is invalid")
48-
normalized_status_code = int(status_code)
46+
if isinstance(status_code, bool) or not isinstance(status_code, int):
47+
raise TypeError("status code must be an integer")
48+
normalized_status_code = status_code
4949
if not (
5050
self._MIN_HTTP_STATUS_CODE
5151
<= normalized_status_code

hyperbrowser/transport/sync.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ def __init__(self, api_key: str, headers: Optional[Mapping[str, str]] = None):
4242
def _normalize_response_status_code(self, response: httpx.Response) -> int:
4343
try:
4444
status_code = response.status_code
45-
if isinstance(status_code, bool):
46-
raise TypeError("boolean status code is invalid")
47-
normalized_status_code = int(status_code)
45+
if isinstance(status_code, bool) or not isinstance(status_code, int):
46+
raise TypeError("status code must be an integer")
47+
normalized_status_code = status_code
4848
if not (
4949
self._MIN_HTTP_STATUS_CODE
5050
<= normalized_status_code

tests/test_transport_response_handling.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ def json(self):
9292
return {}
9393

9494

95+
class _NonIntegerStatusNoContentResponse:
96+
content = b""
97+
text = ""
98+
99+
def __init__(self, status_code):
100+
self.status_code = status_code
101+
102+
def raise_for_status(self) -> None:
103+
return None
104+
105+
def json(self):
106+
return {}
107+
108+
95109
class _BrokenStatusCodeHttpErrorResponse:
96110
content = b""
97111
text = "status error"
@@ -201,6 +215,22 @@ def test_sync_handle_response_with_out_of_range_status_raises_hyperbrowser_error
201215
transport.close()
202216

203217

218+
@pytest.mark.parametrize("status_code", ["200", 200.0])
219+
def test_sync_handle_response_with_non_integer_status_raises_hyperbrowser_error(
220+
status_code,
221+
):
222+
transport = SyncTransport(api_key="test-key")
223+
try:
224+
with pytest.raises(
225+
HyperbrowserError, match="Failed to process response status code"
226+
):
227+
transport._handle_response(
228+
_NonIntegerStatusNoContentResponse(status_code) # type: ignore[arg-type]
229+
)
230+
finally:
231+
transport.close()
232+
233+
204234
def test_sync_handle_response_with_request_error_includes_method_and_url():
205235
transport = SyncTransport(api_key="test-key")
206236
try:
@@ -371,6 +401,25 @@ async def run() -> None:
371401
asyncio.run(run())
372402

373403

404+
@pytest.mark.parametrize("status_code", ["200", 200.0])
405+
def test_async_handle_response_with_non_integer_status_raises_hyperbrowser_error(
406+
status_code,
407+
):
408+
async def run() -> None:
409+
transport = AsyncTransport(api_key="test-key")
410+
try:
411+
with pytest.raises(
412+
HyperbrowserError, match="Failed to process response status code"
413+
):
414+
await transport._handle_response(
415+
_NonIntegerStatusNoContentResponse(status_code) # type: ignore[arg-type]
416+
)
417+
finally:
418+
await transport.close()
419+
420+
asyncio.run(run())
421+
422+
374423
def test_async_handle_response_with_request_error_includes_method_and_url():
375424
async def run() -> None:
376425
transport = AsyncTransport(api_key="test-key")

0 commit comments

Comments
 (0)