"""HttpProviderClient + safe_headers tests.""" from __future__ import annotations import pytest from notify_bridge_core.notifications.http_base import safe_headers class TestSafeHeaders: def test_drops_hop_by_hop(self) -> None: out = safe_headers({ "X-Custom": "ok", "Host": "evil.example.com", "Content-Length": "999", "Transfer-Encoding": "chunked", "Connection": "close", }) assert out == {"X-Custom": "ok"} def test_rejects_crlf_in_value(self) -> None: out = safe_headers({ "X-Custom": "ok", "X-Bad": "value\r\nInjected: yes", }) assert "X-Custom" in out assert "X-Bad" not in out def test_rejects_crlf_in_name(self) -> None: out = safe_headers({ "X-Custom": "ok", "X-Bad\r\nInject": "value", }) assert out == {"X-Custom": "ok"} def test_empty_input(self) -> None: assert safe_headers(None) == {} assert safe_headers({}) == {} @pytest.mark.asyncio async def test_http_base_returns_safe_error_on_invalid_url() -> None: """An obviously-bad URL must not panic or leak the URL verbatim.""" import aiohttp from notify_bridge_core.notifications.http_base import HttpProviderClient async with aiohttp.ClientSession() as sess: client = HttpProviderClient(sess, provider_name="test") # file:// is rejected by the SSRF guard before any HTTP call. result = await client.request("POST", "file:///etc/passwd", json={}) assert result["success"] is False assert "Unsafe URL" in result["error"]