Skip to content

Commit 3d2b829

Browse files
authored
[PR #10029/5f5729d backport][3.11] Defer creation of cookies for client responses until needed (#10033)
1 parent dc61477 commit 3d2b829

File tree

4 files changed

+45
-9
lines changed

4 files changed

+45
-9
lines changed

CHANGES/10029.misc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved performance of creating :class:`aiohttp.ClientResponse` objects when there are no cookies -- by :user:`bdraco`.

aiohttp/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ async def _request(
744744
raise
745745
raise ClientOSError(*exc.args) from exc
746746

747-
if cookies := resp.cookies:
747+
if cookies := resp._cookies:
748748
self._cookie_jar.update_cookies(cookies, resp.url)
749749

750750
# redirects

aiohttp/client_reqrep.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ class ClientResponse(HeadersMixin):
826826
_raw_headers: RawHeaders = None # type: ignore[assignment]
827827

828828
_connection: Optional["Connection"] = None # current connection
829+
_cookies: Optional[SimpleCookie] = None
829830
_continue: Optional["asyncio.Future[bool]"] = None
830831
_source_traceback: Optional[traceback.StackSummary] = None
831832
_session: Optional["ClientSession"] = None
@@ -856,7 +857,6 @@ def __init__(
856857
assert type(url) is URL
857858

858859
self.method = method
859-
self.cookies = SimpleCookie()
860860

861861
self._real_url = url
862862
self._url = url.with_fragment(None) if url.raw_fragment else url
@@ -905,6 +905,16 @@ def _writer(self, writer: Optional["asyncio.Task[None]"]) -> None:
905905
else:
906906
writer.add_done_callback(self.__reset_writer)
907907

908+
@property
909+
def cookies(self) -> SimpleCookie:
910+
if self._cookies is None:
911+
self._cookies = SimpleCookie()
912+
return self._cookies
913+
914+
@cookies.setter
915+
def cookies(self, cookies: SimpleCookie) -> None:
916+
self._cookies = cookies
917+
908918
@reify
909919
def url(self) -> URL:
910920
return self._url
@@ -1068,11 +1078,14 @@ async def start(self, connection: "Connection") -> "ClientResponse":
10681078
self.content = payload
10691079

10701080
# cookies
1071-
for hdr in self.headers.getall(hdrs.SET_COOKIE, ()):
1072-
try:
1073-
self.cookies.load(hdr)
1074-
except CookieError as exc:
1075-
client_logger.warning("Can not load response cookies: %s", exc)
1081+
if cookie_hdrs := self.headers.getall(hdrs.SET_COOKIE, ()):
1082+
cookies = SimpleCookie()
1083+
for hdr in cookie_hdrs:
1084+
try:
1085+
cookies.load(hdr)
1086+
except CookieError as exc:
1087+
client_logger.warning("Can not load response cookies: %s", exc)
1088+
self._cookies = cookies
10761089
return self
10771090

10781091
def _response_eof(self) -> None:

tests/test_client_response.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Tests for aiohttp/client.py
22

3+
import asyncio
34
import gc
45
import sys
56
from typing import Callable
@@ -10,7 +11,7 @@
1011
from yarl import URL
1112

1213
import aiohttp
13-
from aiohttp import http
14+
from aiohttp import ClientSession, http
1415
from aiohttp.client_reqrep import ClientResponse, RequestInfo
1516
from aiohttp.helpers import TimerNoop
1617
from aiohttp.test_utils import make_mocked_coro
@@ -1139,7 +1140,28 @@ def side_effect(*args, **kwargs):
11391140
)
11401141

11411142

1142-
def test_response_real_url(loop, session) -> None:
1143+
def test_response_cookies(
1144+
loop: asyncio.AbstractEventLoop, session: ClientSession
1145+
) -> None:
1146+
response = ClientResponse(
1147+
"get",
1148+
URL("http://python.org"),
1149+
request_info=mock.Mock(),
1150+
writer=WriterMock(),
1151+
continue100=None,
1152+
timer=TimerNoop(),
1153+
traces=[],
1154+
loop=loop,
1155+
session=session,
1156+
)
1157+
cookies = response.cookies
1158+
# Ensure the same cookies object is returned each time
1159+
assert response.cookies is cookies
1160+
1161+
1162+
def test_response_real_url(
1163+
loop: asyncio.AbstractEventLoop, session: ClientSession
1164+
) -> None:
11431165
url = URL("http://def-cl-resp.org/#urlfragment")
11441166
response = ClientResponse(
11451167
"get",

0 commit comments

Comments
 (0)