Skip to content

Commit

Permalink
[3.8] Fix cookie handling (#6638) (#6974)
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]>
(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 <[email protected]>
  • Loading branch information
galaxyfeeder and bratao authored Sep 26, 2022
1 parent 6d4ec02 commit 8cf01ad
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 @@ -61,6 +61,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__(
loop: Optional[asyncio.AbstractEventLoop] = None,
) -> None:
super().__init__(loop=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 @@ -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 8cf01ad

Please sign in to comment.