From b9db34213642afa0c402e80056f697d25be3543a Mon Sep 17 00:00:00 2001 From: privatejava Date: Wed, 25 Feb 2026 01:41:43 +0545 Subject: [PATCH] fix(auth): strip whitespace from HTTP header values to prevent h11 rejection On some Linux systems, `platform.version()` returns a kernel version string with a trailing space (e.g. "#100~22.04.1-Ubuntu SMP ... UTC "). This trailing whitespace violates RFC 7230 field-value grammar, causing h11 to raise `LocalProtocolError: Illegal header value` and making the CLI unable to connect to the API. The existing `_ascii_header_value()` only stripped whitespace in the UnicodeEncodeError fallback path. This change ensures `.strip()` is always applied, matching the behavior that was already intended for the non-ASCII path. --- src/kimi_cli/auth/oauth.py | 4 +-- tests/utils/test_ascii_header_value.py | 40 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 tests/utils/test_ascii_header_value.py diff --git a/src/kimi_cli/auth/oauth.py b/src/kimi_cli/auth/oauth.py index 96d025d96..2976c0565 100644 --- a/src/kimi_cli/auth/oauth.py +++ b/src/kimi_cli/auth/oauth.py @@ -195,10 +195,10 @@ def get_device_id() -> str: def _ascii_header_value(value: str, *, fallback: str = "unknown") -> str: try: value.encode("ascii") - return value + sanitized = value.strip() except UnicodeEncodeError: sanitized = value.encode("ascii", errors="ignore").decode("ascii").strip() - return sanitized or fallback + return sanitized or fallback def _common_headers() -> dict[str, str]: diff --git a/tests/utils/test_ascii_header_value.py b/tests/utils/test_ascii_header_value.py new file mode 100644 index 000000000..5b2f04b06 --- /dev/null +++ b/tests/utils/test_ascii_header_value.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from kimi_cli.auth.oauth import _ascii_header_value + + +def test_strips_trailing_whitespace() -> None: + """platform.version() on some Linux systems returns a trailing space.""" + value = "#100~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Mon Jan 19 17:10:19 UTC " + assert _ascii_header_value(value) == value.strip() + + +def test_strips_leading_whitespace() -> None: + value = " some-value" + assert _ascii_header_value(value) == "some-value" + + +def test_clean_ascii_value_unchanged() -> None: + value = "KimiCLI/1.13.0" + assert _ascii_header_value(value) == value + + +def test_non_ascii_stripped_and_trimmed() -> None: + value = "héllo wörld " + result = _ascii_header_value(value) + assert result == "hllo wrld" + + +def test_empty_after_sanitize_returns_fallback() -> None: + value = "日本語" + assert _ascii_header_value(value) == "unknown" + + +def test_custom_fallback() -> None: + value = "日本語" + assert _ascii_header_value(value, fallback="n/a") == "n/a" + + +def test_whitespace_only_returns_fallback() -> None: + value = " " + assert _ascii_header_value(value) == "unknown"