Skip to content

Commit 8cf01ad

Browse files
galaxyfeederbratao
andauthored
[3.8] Fix cookie handling (#6638) (#6974)
* Fix cookie handling * Fix cookie handling * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update aiohttp/cookiejar.py Co-authored-by: Sam Bull <aa6bs0@sambull.org> Co-authored-by: Bruno Cabral <bruno@potelo.com.br> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Sam Bull <aa6bs0@sambull.org> (cherry picked from commit 916b3ee) <!-- Thank you for your contribution! --> ## What do these changes do? <!-- Please give a short brief about these changes. --> ## Are there changes in behavior for the user? <!-- Outline any notable behaviour for the end users. --> ## Related issue number <!-- Are there any issues opened that will be resolved by merging this change? --> ## Checklist - [ ] I think the code is well written - [ ] Unit tests for the changes exist - [ ] Documentation reflects the changes - [ ] If you provide code modification, please add yourself to `CONTRIBUTORS.txt` * The format is &lt;Name&gt; &lt;Surname&gt;. * Please keep alphabetical order, the file is sorted by names. - [ ] Add a new news fragment into the `CHANGES` folder * name it `<issue_id>.<type>` for example (588.bugfix) * if you don't have an `issue_id` change it to the pr id after creating the pr * ensure type is one of the following: * `.feature`: Signifying a new feature. * `.bugfix`: Signifying a bug fix. * `.doc`: Signifying a documentation improvement. * `.removal`: Signifying a deprecation or removal of public API. * `.misc`: A ticket has been closed, but it is not of interest to users. * Make sure to use full sentences with correct case and punctuation, for example: "Fix issue with non-ascii contents in doctest text files." Co-authored-by: Bruno Cabral <brataodream@gmail.com>
1 parent 6d4ec02 commit 8cf01ad

File tree

4 files changed

+42
-14
lines changed

4 files changed

+42
-14
lines changed

CHANGES/6638.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Do not overwrite cookies with same name and domain when the path is different.

CONTRIBUTORS.txt

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Brian Bouterse
6161
Brian C. Lane
6262
Brian Muller
6363
Bruce Merry
64+
Bruno Souza Cabral
6465
Bryan Kok
6566
Bryce Drennan
6667
Carl George

aiohttp/cookiejar.py

+18-14
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ def __init__(
6565
loop: Optional[asyncio.AbstractEventLoop] = None,
6666
) -> None:
6767
super().__init__(loop=loop)
68-
self._cookies: DefaultDict[str, SimpleCookie[str]] = defaultdict(SimpleCookie)
68+
self._cookies: DefaultDict[Tuple[str, str], SimpleCookie[str]] = defaultdict(
69+
SimpleCookie
70+
)
6971
self._host_only_cookies: Set[Tuple[str, str]] = set()
7072
self._unsafe = unsafe
7173
self._quote_cookie = quote_cookie
@@ -82,7 +84,7 @@ def __init__(
8284
]
8385
self._treat_as_secure_origin = treat_as_secure_origin
8486
self._next_expiration = next_whole_second()
85-
self._expirations: Dict[Tuple[str, str], datetime.datetime] = {}
87+
self._expirations: Dict[Tuple[str, str, str], datetime.datetime] = {}
8688
# #4515: datetime.max may not be representable on 32-bit platforms
8789
self._max_time = self.MAX_TIME
8890
try:
@@ -110,20 +112,20 @@ def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None:
110112

111113
to_del = []
112114
now = datetime.datetime.now(datetime.timezone.utc)
113-
for domain, cookie in self._cookies.items():
115+
for (domain, path), cookie in self._cookies.items():
114116
for name, morsel in cookie.items():
115-
key = (domain, name)
117+
key = (domain, path, name)
116118
if (
117119
key in self._expirations and self._expirations[key] <= now
118120
) or predicate(morsel):
119121
to_del.append(key)
120122

121-
for domain, name in to_del:
122-
key = (domain, name)
123-
self._host_only_cookies.discard(key)
123+
for domain, path, name in to_del:
124+
self._host_only_cookies.discard((domain, name))
125+
key = (domain, path, name)
124126
if key in self._expirations:
125-
del self._expirations[(domain, name)]
126-
self._cookies[domain].pop(name, None)
127+
del self._expirations[(domain, path, name)]
128+
self._cookies[(domain, path)].pop(name, None)
127129

128130
next_expiration = min(self._expirations.values(), default=self._max_time)
129131
try:
@@ -147,9 +149,11 @@ def __len__(self) -> int:
147149
def _do_expiration(self) -> None:
148150
self.clear(lambda x: False)
149151

150-
def _expire_cookie(self, when: datetime.datetime, domain: str, name: str) -> None:
152+
def _expire_cookie(
153+
self, when: datetime.datetime, domain: str, path: str, name: str
154+
) -> None:
151155
self._next_expiration = min(self._next_expiration, when)
152-
self._expirations[(domain, name)] = when
156+
self._expirations[(domain, path, name)] = when
153157

154158
def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None:
155159
"""Update cookies."""
@@ -211,7 +215,7 @@ def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> No
211215
) + datetime.timedelta(seconds=delta_seconds)
212216
except OverflowError:
213217
max_age_expiration = self._max_time
214-
self._expire_cookie(max_age_expiration, domain, name)
218+
self._expire_cookie(max_age_expiration, domain, path, name)
215219
except ValueError:
216220
cookie["max-age"] = ""
217221

@@ -220,11 +224,11 @@ def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> No
220224
if expires:
221225
expire_time = self._parse_date(expires)
222226
if expire_time:
223-
self._expire_cookie(expire_time, domain, name)
227+
self._expire_cookie(expire_time, domain, path, name)
224228
else:
225229
cookie["expires"] = ""
226230

227-
self._cookies[domain][name] = cookie
231+
self._cookies[(domain, path)][name] = cookie
228232

229233
self._do_expiration()
230234

tests/test_cookiejar.py

+22
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,28 @@ async def make_jar():
664664
# Assert that there is a cookie.
665665
assert len(jar) == 1
666666

667+
def test_path_filter_diff_folder_same_name(self) -> None:
668+
async def make_jar():
669+
return CookieJar(unsafe=True)
670+
671+
jar = self.loop.run_until_complete(make_jar())
672+
673+
jar.update_cookies(
674+
SimpleCookie("path-cookie=zero; Domain=pathtest.com; Path=/; ")
675+
)
676+
jar.update_cookies(
677+
SimpleCookie("path-cookie=one; Domain=pathtest.com; Path=/one; ")
678+
)
679+
self.assertEqual(len(jar), 2)
680+
681+
jar_filtered = jar.filter_cookies(URL("http://pathtest.com/"))
682+
self.assertEqual(len(jar_filtered), 1)
683+
self.assertEqual(jar_filtered["path-cookie"].value, "zero")
684+
685+
jar_filtered = jar.filter_cookies(URL("http://pathtest.com/one"))
686+
self.assertEqual(len(jar_filtered), 1)
687+
self.assertEqual(jar_filtered["path-cookie"].value, "one")
688+
667689

668690
async def test_dummy_cookie_jar() -> None:
669691
cookie = SimpleCookie("foo=bar; Domain=example.com;")

0 commit comments

Comments
 (0)