From a6352713a5a05b886cc10deb7aaac4d78b48b27e Mon Sep 17 00:00:00 2001 From: Bruno Cabral Date: Mon, 28 Feb 2022 17:37:30 -0300 Subject: [PATCH 1/4] Fix cookie handling --- CONTRIBUTORS.txt | 1 + aiohttp/cookiejar.py | 25 +++++++++++++------------ tests/test_cookiejar.py | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index a9f82da88ef..0432d7b6d80 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -63,6 +63,7 @@ Brian Bouterse Brian C. Lane Brian Muller Bruce Merry +Bruno Souza Cabral Bryan Kok Bryce Drennan Carl George diff --git a/aiohttp/cookiejar.py b/aiohttp/cookiejar.py index a16a04d4bb9..dd60aabd049 100644 --- a/aiohttp/cookiejar.py +++ b/aiohttp/cookiejar.py @@ -65,7 +65,7 @@ def __init__( treat_as_secure_origin: Union[StrOrURL, List[StrOrURL], None] = None ) -> None: self._loop = asyncio.get_running_loop() - self._cookies: DefaultDict[str, SimpleCookie[str]] = defaultdict(SimpleCookie) + self._cookies: DefaultDict[Tuple[str, str], SimpleCookie[str]] = defaultdict(SimpleCookie) self._host_only_cookies: Set[Tuple[str, str]] = set() self._unsafe = unsafe self._quote_cookie = quote_cookie @@ -82,7 +82,7 @@ def __init__( ] self._treat_as_secure_origin = treat_as_secure_origin self._next_expiration = next_whole_second() - self._expirations: Dict[Tuple[str, str], datetime.datetime] = {} + self._expirations: Dict[Tuple[str, str, str], datetime.datetime] = {} # #4515: datetime.max may not be representable on 32-bit platforms self._max_time = self.MAX_TIME try: @@ -110,20 +110,21 @@ def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: to_del = [] now = datetime.datetime.now(datetime.timezone.utc) - for domain, cookie in self._cookies.items(): + for (domain, path), cookie in self._cookies.items(): for name, morsel in cookie.items(): - key = (domain, name) + key = (domain, path, name) if ( key in self._expirations and self._expirations[key] <= now ) or predicate(morsel): to_del.append(key) - for domain, name in to_del: + for domain, path, name in to_del: key = (domain, name) self._host_only_cookies.discard(key) + key = (domain, path, name) if key in self._expirations: - del self._expirations[(domain, name)] - self._cookies[domain].pop(name, None) + del self._expirations[(domain, path, name)] + self._cookies[(domain, path)].pop(name, None) next_expiration = min(self._expirations.values(), default=self._max_time) try: @@ -147,9 +148,9 @@ def __len__(self) -> int: def _do_expiration(self) -> None: self.clear(lambda x: False) - def _expire_cookie(self, when: datetime.datetime, domain: str, name: str) -> None: + def _expire_cookie(self, when: datetime.datetime, domain: str, path: str, name: str) -> None: self._next_expiration = min(self._next_expiration, when) - self._expirations[(domain, name)] = when + self._expirations[(domain, path, name)] = when def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> None: """Update cookies.""" @@ -211,7 +212,7 @@ def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> No ) + datetime.timedelta(seconds=delta_seconds) except OverflowError: max_age_expiration = self._max_time - self._expire_cookie(max_age_expiration, domain, name) + self._expire_cookie(max_age_expiration, domain, path, name) except ValueError: cookie["max-age"] = "" @@ -220,11 +221,11 @@ def update_cookies(self, cookies: LooseCookies, response_url: URL = URL()) -> No if expires: expire_time = self._parse_date(expires) if expire_time: - self._expire_cookie(expire_time, domain, name) + self._expire_cookie(expire_time, domain, path, name) else: cookie["expires"] = "" - self._cookies[domain][name] = cookie + self._cookies[(domain, path)][name] = cookie self._do_expiration() diff --git a/tests/test_cookiejar.py b/tests/test_cookiejar.py index a82b0d471b2..6e4ad2458e8 100644 --- a/tests/test_cookiejar.py +++ b/tests/test_cookiejar.py @@ -681,6 +681,25 @@ async def make_jar(): # Assert that there is a cookie. assert len(jar) == 1 + def test_path_filter_diff_folder_same_name(self) -> None: + + async def make_jar(): + return CookieJar(unsafe=True) + + jar = self.loop.run_until_complete(make_jar()) + + jar.update_cookies(SimpleCookie("path-cookie=zero; Domain=pathtest.com; Path=/; ")) + jar.update_cookies(SimpleCookie("path-cookie=one; Domain=pathtest.com; Path=/one; ")) + self.assertEqual(len(jar), 2) + + jar_filtered = jar.filter_cookies(URL("http://pathtest.com/")) + self.assertEqual(len(jar_filtered), 1) + self.assertEqual(jar_filtered['path-cookie'].value, "zero") + + jar_filtered = jar.filter_cookies(URL("http://pathtest.com/one")) + self.assertEqual(len(jar_filtered), 1) + self.assertEqual(jar_filtered['path-cookie'].value, "one") + async def test_dummy_cookie_jar() -> None: cookie = SimpleCookie("foo=bar; Domain=example.com;") From ea9ebae68cbb35d9fce872e49dad91de58a9182a Mon Sep 17 00:00:00 2001 From: Bruno Cabral Date: Mon, 28 Feb 2022 17:44:47 -0300 Subject: [PATCH 2/4] Fix cookie handling --- CHANGES/6638.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/6638.bugfix diff --git a/CHANGES/6638.bugfix b/CHANGES/6638.bugfix new file mode 100644 index 00000000000..8154dcfe3f3 --- /dev/null +++ b/CHANGES/6638.bugfix @@ -0,0 +1 @@ +Do not overwrite cookies with same name and domain when the path is different. From 8a8de312a49f238134af6249eed2e015c83e4a23 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 28 Feb 2022 20:46:26 +0000 Subject: [PATCH 3/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- aiohttp/cookiejar.py | 8 ++++++-- tests/test_cookiejar.py | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/aiohttp/cookiejar.py b/aiohttp/cookiejar.py index dd60aabd049..796ff3ccb3c 100644 --- a/aiohttp/cookiejar.py +++ b/aiohttp/cookiejar.py @@ -65,7 +65,9 @@ def __init__( treat_as_secure_origin: Union[StrOrURL, List[StrOrURL], None] = None ) -> None: self._loop = asyncio.get_running_loop() - self._cookies: DefaultDict[Tuple[str, str], SimpleCookie[str]] = defaultdict(SimpleCookie) + self._cookies: DefaultDict[Tuple[str, str], SimpleCookie[str]] = defaultdict( + SimpleCookie + ) self._host_only_cookies: Set[Tuple[str, str]] = set() self._unsafe = unsafe self._quote_cookie = quote_cookie @@ -148,7 +150,9 @@ def __len__(self) -> int: def _do_expiration(self) -> None: self.clear(lambda x: False) - def _expire_cookie(self, when: datetime.datetime, domain: str, path: str, name: str) -> None: + def _expire_cookie( + self, when: datetime.datetime, domain: str, path: str, name: str + ) -> None: self._next_expiration = min(self._next_expiration, when) self._expirations[(domain, path, name)] = when diff --git a/tests/test_cookiejar.py b/tests/test_cookiejar.py index 6e4ad2458e8..84e3727797e 100644 --- a/tests/test_cookiejar.py +++ b/tests/test_cookiejar.py @@ -682,23 +682,26 @@ async def make_jar(): assert len(jar) == 1 def test_path_filter_diff_folder_same_name(self) -> None: - async def make_jar(): return CookieJar(unsafe=True) jar = self.loop.run_until_complete(make_jar()) - jar.update_cookies(SimpleCookie("path-cookie=zero; Domain=pathtest.com; Path=/; ")) - jar.update_cookies(SimpleCookie("path-cookie=one; Domain=pathtest.com; Path=/one; ")) + jar.update_cookies( + SimpleCookie("path-cookie=zero; Domain=pathtest.com; Path=/; ") + ) + jar.update_cookies( + SimpleCookie("path-cookie=one; Domain=pathtest.com; Path=/one; ") + ) self.assertEqual(len(jar), 2) jar_filtered = jar.filter_cookies(URL("http://pathtest.com/")) self.assertEqual(len(jar_filtered), 1) - self.assertEqual(jar_filtered['path-cookie'].value, "zero") + self.assertEqual(jar_filtered["path-cookie"].value, "zero") jar_filtered = jar.filter_cookies(URL("http://pathtest.com/one")) self.assertEqual(len(jar_filtered), 1) - self.assertEqual(jar_filtered['path-cookie'].value, "one") + self.assertEqual(jar_filtered["path-cookie"].value, "one") async def test_dummy_cookie_jar() -> None: From 58ed64fd45d341043940becfa9d06a3143f208b5 Mon Sep 17 00:00:00 2001 From: Bruno Cabral Date: Mon, 28 Feb 2022 20:39:45 -0300 Subject: [PATCH 4/4] Update aiohttp/cookiejar.py Co-authored-by: Sam Bull --- aiohttp/cookiejar.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aiohttp/cookiejar.py b/aiohttp/cookiejar.py index 796ff3ccb3c..0ff9532406f 100644 --- a/aiohttp/cookiejar.py +++ b/aiohttp/cookiejar.py @@ -121,8 +121,7 @@ def clear(self, predicate: Optional[ClearCookiePredicate] = None) -> None: to_del.append(key) for domain, path, name in to_del: - key = (domain, name) - self._host_only_cookies.discard(key) + self._host_only_cookies.discard((domain, name)) key = (domain, path, name) if key in self._expirations: del self._expirations[(domain, path, name)]