Skip to content

Commit

Permalink
Fix cookie handling (aio-libs#6638)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
4 people committed Mar 7, 2022
1 parent 7514f22 commit 916b3ee
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGES/6638.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Do not overwrite cookies with same name and domain when the path is different.
1 change: 1 addition & 0 deletions CONTRIBUTORS.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Brian Bouterse
Brian C. Lane
Brian Muller
Bruce Merry
Bruno Souza Cabral
Bryan Kok
Bryce Drennan
Carl George
Expand Down
32 changes: 18 additions & 14 deletions aiohttp/cookiejar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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[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
Expand All @@ -82,7 +84,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:
Expand Down Expand Up @@ -110,20 +112,20 @@ 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:
key = (domain, name)
self._host_only_cookies.discard(key)
for domain, path, name in to_del:
self._host_only_cookies.discard((domain, name))
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:
Expand All @@ -147,9 +149,11 @@ 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."""
Expand Down Expand Up @@ -211,7 +215,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"] = ""

Expand All @@ -220,11 +224,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()

Expand Down
22 changes: 22 additions & 0 deletions tests/test_cookiejar.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,28 @@ 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;")
Expand Down

0 comments on commit 916b3ee

Please sign in to comment.