Skip to content

Commit 8dd6ba0

Browse files
committed
Migrate to using aiohttp
1 parent 0624fdd commit 8dd6ba0

File tree

2 files changed

+282
-6
lines changed

2 files changed

+282
-6
lines changed

onvif/zeep_aiohttp.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,24 @@ def _aiohttp_to_httpx_response(
9898
# Store cookies if any
9999
if aiohttp_response.cookies:
100100
for cookie in aiohttp_response.cookies.values():
101-
httpx_response.cookies.set(
102-
cookie.key,
103-
cookie.value,
104-
domain=cookie.get("domain"),
105-
path=cookie.get("path"),
106-
)
101+
# Extract all cookie attributes
102+
cookie_attrs = {}
103+
if cookie.get("domain"):
104+
cookie_attrs["domain"] = cookie.get("domain")
105+
if cookie.get("path"):
106+
cookie_attrs["path"] = cookie.get("path")
107+
if cookie.get("secure"):
108+
cookie_attrs["secure"] = True
109+
if cookie.get("httponly"):
110+
cookie_attrs["httpOnly"] = True
111+
if cookie.get("max-age"):
112+
cookie_attrs["max_age"] = int(cookie.get("max-age"))
113+
if cookie.get("expires"):
114+
cookie_attrs["expires"] = cookie.get("expires")
115+
if cookie.get("samesite"):
116+
cookie_attrs["samesite"] = cookie.get("samesite")
117+
118+
httpx_response.cookies.set(cookie.key, cookie.value, **cookie_attrs)
107119

108120
return httpx_response
109121

tests/test_zeep_transport.py

Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,3 +585,267 @@ async def test_provided_session_not_closed():
585585
# Provided session should not be closed
586586
mock_session.close.assert_not_called()
587587
assert transport.session == mock_session
588+
589+
590+
@pytest.mark.asyncio
591+
async def test_cookie_conversion_httpx_basic():
592+
"""Test basic cookie conversion from aiohttp to httpx response."""
593+
transport = AIOHTTPTransport()
594+
595+
# Create aiohttp cookies
596+
from http.cookies import SimpleCookie
597+
598+
cookies = SimpleCookie()
599+
cookies["session"] = "abc123"
600+
cookies["session"]["domain"] = ".example.com"
601+
cookies["session"]["path"] = "/api"
602+
cookies["session"]["secure"] = True
603+
cookies["session"]["httponly"] = True
604+
cookies["session"]["max-age"] = "3600"
605+
606+
cookies["user"] = "john_doe"
607+
cookies["user"]["domain"] = "example.com"
608+
cookies["user"]["path"] = "/"
609+
610+
# Mock aiohttp response
611+
mock_response = Mock(spec=aiohttp.ClientResponse)
612+
mock_response.status = 200
613+
mock_response.headers = {}
614+
mock_response.method = "POST"
615+
mock_response.url = "http://example.com"
616+
mock_response.charset = "utf-8"
617+
mock_response.cookies = cookies
618+
mock_response.raise_for_status = Mock()
619+
mock_response.read = AsyncMock(return_value=b"test")
620+
621+
mock_session = Mock(spec=aiohttp.ClientSession)
622+
mock_session.post = AsyncMock(return_value=mock_response)
623+
transport.session = mock_session
624+
625+
# Make request
626+
result = await transport.post("http://example.com", "test", {})
627+
628+
# Verify cookies in httpx response
629+
assert "session" in result.cookies
630+
assert result.cookies["session"] == "abc123"
631+
assert "user" in result.cookies
632+
assert result.cookies["user"] == "john_doe"
633+
634+
635+
@pytest.mark.asyncio
636+
async def test_cookie_conversion_requests_basic():
637+
"""Test basic cookie conversion from aiohttp to requests response."""
638+
transport = AIOHTTPTransport()
639+
640+
# Create aiohttp cookies
641+
from http.cookies import SimpleCookie
642+
643+
cookies = SimpleCookie()
644+
cookies["token"] = "xyz789"
645+
cookies["token"]["domain"] = ".api.example.com"
646+
cookies["token"]["path"] = "/v1"
647+
cookies["token"]["secure"] = True
648+
649+
# Mock aiohttp response
650+
mock_response = Mock(spec=aiohttp.ClientResponse)
651+
mock_response.status = 200
652+
mock_response.headers = {}
653+
mock_response.charset = "utf-8"
654+
mock_response.cookies = cookies
655+
mock_response.raise_for_status = Mock()
656+
mock_response.read = AsyncMock(return_value=b"test")
657+
658+
mock_session = Mock(spec=aiohttp.ClientSession)
659+
mock_session.get = AsyncMock(return_value=mock_response)
660+
transport.session = mock_session
661+
662+
# Make request
663+
result = await transport.get("http://api.example.com/v1/data")
664+
665+
# Verify cookies in requests response
666+
assert "token" in result.cookies
667+
assert result.cookies["token"] == "xyz789"
668+
669+
670+
@pytest.mark.asyncio
671+
async def test_cookie_attributes_httpx():
672+
"""Test that cookie attributes are properly preserved in httpx response."""
673+
transport = AIOHTTPTransport()
674+
675+
# Create cookie with all attributes
676+
from http.cookies import SimpleCookie
677+
678+
cookies = SimpleCookie()
679+
cookies["auth"] = "secret123"
680+
cookies["auth"]["domain"] = ".secure.com"
681+
cookies["auth"]["path"] = "/admin"
682+
cookies["auth"]["secure"] = True
683+
cookies["auth"]["httponly"] = True
684+
cookies["auth"]["samesite"] = "Strict"
685+
cookies["auth"]["max-age"] = "7200"
686+
687+
# Mock response
688+
mock_response = Mock(spec=aiohttp.ClientResponse)
689+
mock_response.status = 200
690+
mock_response.headers = {}
691+
mock_response.method = "POST"
692+
mock_response.url = "https://secure.com/admin"
693+
mock_response.charset = "utf-8"
694+
mock_response.cookies = cookies
695+
mock_response.raise_for_status = Mock()
696+
mock_response.read = AsyncMock(return_value=b"secure")
697+
698+
mock_session = Mock(spec=aiohttp.ClientSession)
699+
mock_session.post = AsyncMock(return_value=mock_response)
700+
transport.session = mock_session
701+
702+
# Make request
703+
result = await transport.post("https://secure.com/admin", "login", {})
704+
705+
# Check cookie exists
706+
assert "auth" in result.cookies
707+
assert result.cookies["auth"] == "secret123"
708+
709+
# Note: httpx.Cookies doesn't expose all attributes directly,
710+
# but they should be preserved internally for cookie jar operations
711+
712+
713+
@pytest.mark.asyncio
714+
async def test_multiple_cookies():
715+
"""Test handling multiple cookies."""
716+
transport = AIOHTTPTransport()
717+
718+
# Create multiple cookies
719+
from http.cookies import SimpleCookie
720+
721+
cookies = SimpleCookie()
722+
for i in range(5):
723+
cookie_name = f"cookie{i}"
724+
cookies[cookie_name] = f"value{i}"
725+
cookies[cookie_name]["domain"] = ".example.com"
726+
cookies[cookie_name]["path"] = f"/path{i}"
727+
728+
# Mock response
729+
mock_response = Mock(spec=aiohttp.ClientResponse)
730+
mock_response.status = 200
731+
mock_response.headers = {}
732+
mock_response.method = "GET"
733+
mock_response.url = "http://example.com"
734+
mock_response.charset = "utf-8"
735+
mock_response.cookies = cookies
736+
mock_response.raise_for_status = Mock()
737+
mock_response.read = AsyncMock(return_value=b"multi")
738+
739+
mock_session = Mock(spec=aiohttp.ClientSession)
740+
mock_session.get = AsyncMock(return_value=mock_response)
741+
transport.session = mock_session
742+
743+
# Make request
744+
result = await transport.get("http://example.com")
745+
746+
# Verify all cookies
747+
for i in range(5):
748+
cookie_name = f"cookie{i}"
749+
assert cookie_name in result.cookies
750+
assert result.cookies[cookie_name] == f"value{i}"
751+
752+
753+
@pytest.mark.asyncio
754+
async def test_empty_cookies():
755+
"""Test handling when no cookies are present."""
756+
transport = AIOHTTPTransport()
757+
758+
# Mock response without cookies
759+
from http.cookies import SimpleCookie
760+
761+
mock_response = Mock(spec=aiohttp.ClientResponse)
762+
mock_response.status = 200
763+
mock_response.headers = {}
764+
mock_response.method = "GET"
765+
mock_response.url = "http://example.com"
766+
mock_response.charset = "utf-8"
767+
mock_response.cookies = SimpleCookie() # Empty cookies
768+
mock_response.raise_for_status = Mock()
769+
mock_response.read = AsyncMock(return_value=b"nocookies")
770+
771+
mock_session = Mock(spec=aiohttp.ClientSession)
772+
mock_session.get = AsyncMock(return_value=mock_response)
773+
transport.session = mock_session
774+
775+
# Make request
776+
result = await transport.get("http://example.com")
777+
778+
# Verify empty cookies
779+
assert len(result.cookies) == 0
780+
781+
782+
@pytest.mark.asyncio
783+
async def test_cookie_encoding():
784+
"""Test cookies with special characters."""
785+
transport = AIOHTTPTransport()
786+
787+
# Create cookies with special chars
788+
from http.cookies import SimpleCookie
789+
790+
cookies = SimpleCookie()
791+
cookies["data"] = "hello%20world%21" # URL encoded
792+
cookies["unicode"] = "café"
793+
794+
# Mock response
795+
mock_response = Mock(spec=aiohttp.ClientResponse)
796+
mock_response.status = 200
797+
mock_response.headers = {}
798+
mock_response.charset = "utf-8"
799+
mock_response.cookies = cookies
800+
mock_response.raise_for_status = Mock()
801+
mock_response.read = AsyncMock(return_value=b"encoded")
802+
803+
mock_session = Mock(spec=aiohttp.ClientSession)
804+
mock_session.get = AsyncMock(return_value=mock_response)
805+
transport.session = mock_session
806+
807+
# Make request
808+
result = await transport.get("http://example.com")
809+
810+
# Verify encoded cookies
811+
assert "data" in result.cookies
812+
assert result.cookies["data"] == "hello%20world%21"
813+
assert "unicode" in result.cookies
814+
assert result.cookies["unicode"] == "café"
815+
816+
817+
@pytest.mark.asyncio
818+
async def test_cookie_jar_type():
819+
"""Test that cookies are stored in appropriate jar types."""
820+
transport = AIOHTTPTransport()
821+
822+
from http.cookies import SimpleCookie
823+
824+
cookies = SimpleCookie()
825+
cookies["test"] = "value"
826+
827+
# Mock response
828+
mock_response = Mock(spec=aiohttp.ClientResponse)
829+
mock_response.status = 200
830+
mock_response.headers = {}
831+
mock_response.method = "POST"
832+
mock_response.url = "http://example.com"
833+
mock_response.charset = "utf-8"
834+
mock_response.cookies = cookies
835+
mock_response.raise_for_status = Mock()
836+
mock_response.read = AsyncMock(return_value=b"jar")
837+
838+
mock_session = Mock(spec=aiohttp.ClientSession)
839+
mock_session.post = AsyncMock(return_value=mock_response)
840+
transport.session = mock_session
841+
842+
# Test httpx response
843+
httpx_result = await transport.post("http://example.com", "test", {})
844+
assert isinstance(httpx_result.cookies, httpx.Cookies)
845+
846+
# Test requests response
847+
mock_session.get = AsyncMock(return_value=mock_response)
848+
requests_result = await transport.get("http://example.com")
849+
# In requests, cookies can be SimpleCookie or CookieJar
850+
assert hasattr(requests_result.cookies, "__getitem__")
851+
assert "test" in requests_result.cookies

0 commit comments

Comments
 (0)