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 <[email protected]>

Co-authored-by: Bruno Cabral <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Sam Bull <[email protected]>
  • Loading branch information
4 people authored and galaxyfeeder committed Aug 23, 2022
1 parent cc6dc0c commit 2b136ce
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 17 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 @@ -60,6 +60,7 @@ Brian Bouterse
Brian C. Lane
Brian Muller
Bruce Merry
Bruno Souza Cabral
Bryan Kok
Bryce Drennan
Carl George
Expand Down
36 changes: 19 additions & 17 deletions aiohttp/cookiejar.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ def __init__(
treat_as_secure_origin: Union[StrOrURL, List[StrOrURL], None] = None,
loop: Optional[asyncio.AbstractEventLoop] = None,
) -> None:
super().__init__(loop=loop)
self._cookies = defaultdict(
self._loop = asyncio.get_running_loop()
self._cookies: DefaultDict[Tuple[str, str], SimpleCookie[str]] = defaultdict(
SimpleCookie
) # type: DefaultDict[str, SimpleCookie[str]]
self._host_only_cookies = set() # type: Set[Tuple[str, str]]
)
self._host_only_cookies: Set[Tuple[str, str]] = set()
self._unsafe = unsafe
self._quote_cookie = quote_cookie
if treat_as_secure_origin is None:
Expand All @@ -84,7 +84,7 @@ def __init__(
]
self._treat_as_secure_origin = treat_as_secure_origin
self._next_expiration = next_whole_second()
self._expirations = {} # type: 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 @@ -112,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 @@ -149,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 @@ -213,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 @@ -222,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 @@ -664,6 +664,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 2b136ce

Please sign in to comment.