aio-libs / aiohttp

Asynchronous HTTP client/server framework for asyncio and Python
https://docs.aiohttp.org
Other
15.18k stars 2.02k forks source link

Support for setting partitioned cookies #9870

Open FeldrinH opened 2 weeks ago

FeldrinH commented 2 weeks ago

Is your feature request related to a problem?

I need to use partitioned cookies to set cookies in contexts where third-party cookies are otherwise restricted.

Describe the solution you'd like

A recent addition to the Set-Cookie header is the ability to mark cookies as partitioned (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#partitioned, https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies).

StreamResponse.set_cookie should support setting partitioned cookies, e.g. using a partitioned=True keyword argument.

Describe alternatives you've considered

I can create a 'Set-Cookie' header manually, but would have to figure out edge cases with encoding and escaping special characters myself. This would be inconvenient and probably error-prone.

Related component

Server

Additional context

No response

Code of Conduct

Dreamsorcerer commented 2 weeks ago

To be clear, you only need to set the flag when sending cookies? You're not asking for partitioned storage when receiving them (which would be a lot more work)?

bdraco commented 2 weeks ago

I'm pretty sure this is a problem in Python itself and is fixed in Python 3.13+

Will need to check when I'm back at my desk

bdraco commented 2 weeks ago
if sys.version_info[:2] < (3, 14):
    from http import cookies

    # See: https://github.com/python/cpython/issues/112713
    cookies.Morsel._reserved["partitioned"] = "partitioned"  # type: ignore[attr-defined]
    cookies.Morsel._flags.add("partitioned")  # type: ignore[attr-defined]

That should work as a workaround if you can't upgrade to Python 3.13

bdraco commented 2 weeks ago

Looks like https://github.com/python/cpython/pull/112714 didn't actually merge into 3.13 so the guard might need to be (3, 14) instead

Dreamsorcerer commented 2 weeks ago

For setting them, we'd need to add the parameters though: https://github.com/aio-libs/aiohttp/blob/4adb0616a6de8351c45779048610081e000f7c6a/aiohttp/helpers.py#L930

Should be a nice easy PR for anyone wanting to volunteer.

Dreamsorcerer commented 2 weeks ago

Yeah, so it is rejected currently:

>>> m["partitioned"] = "1"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.9/http/cookies.py", line 312, in __setitem__
    raise CookieError("Invalid attribute %r" % (K,))
http.cookies.CookieError: Invalid attribute 'partitioned'

So, will need that PR merged in cpython before we can do anything here.

FeldrinH commented 2 weeks ago

Would it be possible for aiohttp to provide some kind of polyfill/backport of this feature? Waiting for Python 3.14, which comes out next year and will take potentially years to roll out to production servers does not seem ideal.

Dreamsorcerer commented 2 weeks ago

Seems like we could include the hack as shown above: https://github.com/aio-libs/aiohttp/issues/9870#issuecomment-2476334346

I think we'd atleast want to know that the upstream PR has been merged and which version it will be released in first though.

asvetlov commented 2 weeks ago

I'm strongly against monkey-patching stdlib for adding new features. The monkeypatching could be acceptable after careful thinking for fixing stdlib bugs; we did it in aiohttp several times. IIRC check_hostname from SSL had a bug for example. But for a new feature this approach is much more questionable.

Plus, if aiohttp user really need CHIPS we provide low-level resp.cookies property already. If an application patches stdlib to make a particular web service work -- it's totally ok. But if aiohttp wants the same -- please don't.

I can imagine a workaround for aiohttp itself though. We can copy ./Lib/http/cookies.py from stdlib to aiohttp, patch it and ship as a private vendored aiohttp file. Maybe tests for it are not required; we trust CPython. By this, we are avoiding potential breaking problems from wild http.cookies change in upcoming python releases. Who knows the future CPython changes?

Dreamsorcerer commented 2 weeks ago

We can also just add the parameter without a version check. Then users can do the monkeypatch on older releases if they need it.

asvetlov commented 2 weeks ago

Works for me as well, and much less code to maintain