| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c85ccf1 commit 1689b57
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -106,8 +106,13 @@ class StdioServerParameters(BaseModel): | |||
| 106 | 106 | encoding: str = "utf-8" | |
| 107 | 107 | """Text encoding for messages to and from the server.""" | |
| 108 | 108 | ||
| 109 | - encoding_error_handler: Literal["strict", "ignore", "replace"] = "strict" | ||
| 110 | - """Encoding error handler; see https://docs.python.org/3/library/codecs.html#error-handlers.""" | ||
| 109 | + encoding_error_handler: Literal["strict", "ignore", "replace"] = "replace" | ||
| 110 | + """Encoding error handler; see https://docs.python.org/3/library/codecs.html#error-handlers. | ||
| 111 | + | ||
| 112 | + Defaults to ``"replace"`` so malformed bytes from a buggy server become U+FFFD and surface | ||
| 113 | + as an in-stream JSON parse error (kept alive for subsequent valid messages) instead of | ||
| 114 | + crashing the transport task group. This mirrors the server-side stdin hardening. | ||
| 115 | + """ | ||
| 111 | 116 | ||
| 112 | 117 | ||
| 113 | 118 | @asynccontextmanager | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -307,6 +307,31 @@ async def test_invalid_json_from_the_server_surfaces_as_an_in_stream_exception( | |||
| 307 | 307 | assert await _next_message(read_stream) == ping | |
| 308 | 308 | ||
| 309 | 309 | ||
| 310 | + @pytest.mark.anyio | ||
| 311 | + async def test_invalid_utf8_mid_session_surfaces_as_an_in_stream_exception( | ||
| 312 | + monkeypatch: pytest.MonkeyPatch, | ||
| 313 | + ) -> None: | ||
| 314 | + """A line with non-UTF-8 bytes is surfaced as a parse error, not a transport crash. | ||
| 315 | + | ||
| 316 | + Regression test for a buggy server emitting malformed bytes mid-session: the default | ||
| 317 | + ``encoding_error_handler="replace"`` turns the bad bytes into U+FFFD so the line fails | ||
| 318 | + JSON validation and is delivered as an Exception, keeping the transport alive for the | ||
| 319 | + valid messages that follow (instead of a UnicodeDecodeError tearing down the task group). | ||
| 320 | + """ | ||
| 321 | + ping = JSONRPCRequest(jsonrpc="2.0", id=1, method="ping") | ||
| 322 | + process = FakeProcess(on_stdin_close=lambda: process.exit(0)) | ||
| 323 | + | ||
| 324 | + install_fake_process(monkeypatch, process) | ||
| 325 | + | ||
| 326 | + with anyio.fail_after(5): | ||
| 327 | + async with stdio_client(FAKE_PARAMS) as (read_stream, _): | ||
| 328 | + await process.feed(b"\xff\xfe\n" + _line(ping)) | ||
| 329 | + | ||
| 330 | + error = await read_stream.receive() | ||
| 331 | + assert isinstance(error, ValueError) | ||
| 332 | + assert await _next_message(read_stream) == ping | ||
| 333 | + | ||
| 334 | + | ||
| 310 | 335 | @pytest.mark.anyio | |
| 311 | 336 | async def test_a_server_that_dies_before_responding_fails_initialize_with_connection_closed( | |
| 312 | 337 | monkeypatch: pytest.MonkeyPatch, | |
| Back | FazBrowse Home | New Git URL |
0 commit comments