Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aiohttp ignoring cookie_jar quote_cookie parameter #9336

Open
1 task done
TomerSalt opened this issue Sep 29, 2024 · 4 comments
Open
1 task done

aiohttp ignoring cookie_jar quote_cookie parameter #9336

TomerSalt opened this issue Sep 29, 2024 · 4 comments
Labels

Comments

@TomerSalt
Copy link

TomerSalt commented Sep 29, 2024

Describe the bug

sess = aiohttp.ClientSession(connector=conn, cookie_jar=aiohttp.CookieJar(quote_cookie=False)).request(...)

When using an client session object with a cookie jar with the cookie quoting routine disabled the requests sent still uses quoting routine when invoking the request:

[client_reqrep.py:468] ClientRequest().update_cookies():

def update_cookies(self, cookies: Optional[LooseCookies]) -> None:
        """Update request cookies header."""
        if not cookies:
            return

        c = SimpleCookie()
        .
        .
        .
        self.headers[hdrs.COOKIE] = c.output(header="", sep=";").strip()

The variable c used to output the cookie is a SimpleCookie object which defaults to using the quoting routine.
therefor when for example received a cookie with value such as id=!IagQHEStKHLB3DFBAufSQIeK+Olw= the header will output as Cookie: id="!IagQHEStKHLB3DFBAufSQIeK+Olw=".

A possible fix is to add a method to the CookieJar object like is_quote_disabled() and then in the update cookies use the self.session.is_quoting_disabled() to specifically handle the cookie in such case. i used:

self.headers[hdrs.COOKIE] = '; '.join([f"{name}={mrsl.value}" for name,mrsl in cookies.items()])

To Reproduce

use the following script to reproduce:

import aiohttp
import asyncio

async def req():
    tcp_conn = aiohttp.TCPConnector(limit=10, force_close=True)
    c_jar = aiohttp.CookieJar(quote_cookie=False)
    sess = aiohttp.ClientSession(connector=tcp_conn, cookie_jar=c_jar)
    cookies = {"name": "val="}
    resp = await sess.request(url="http://localhost:8000/", method="GET", cookies=cookies)
    print(resp.request_info.headers.get("Cookie")) # name="val="
    await sess.close()

asyncio.run(req())

Expected behavior

When specifying quote_cookie to False, cookie which by specifications are supposed to be quoted shouldn't be quoted because of the implicit flag.

Logs/tracebacks

-

Python Version

$ python --version
Python 3.9.6

aiohttp Version

$ python -m pip show aiohttp
Version: 3.10.5

multidict Version

$ python -m pip show multidict
Version: 6.1.0

yarl Version

$ python -m pip show yarl
Version: 1.11.1

OS

Mac OS

Related component

Client

Additional context

No response

Code of Conduct

  • I agree to follow the aio-libs Code of Conduct
@TomerSalt TomerSalt added the bug label Sep 29, 2024
@Dreamsorcerer
Copy link
Member

Please create a complete reproducer (or better, a failing test in a PR).

@Dreamsorcerer Dreamsorcerer added the needs-info Issue is lacking sufficient information and will be closed if not provided label Sep 29, 2024
@TomerSalt
Copy link
Author

import aiohttp
import asyncio

async def req():
tcp_conn = aiohttp.TCPConnector(limit=10, force_close=True)
c_jar = aiohttp.CookieJar(quote_cookie=False)
sess = aiohttp.ClientSession(connector=tcp_conn, cookie_jar=c_jar)
cookies = {"name": "val="}
resp = await sess.request(url="http://localhost:8000/", method="GET", cookies=cookies)
print(resp.request_info.headers.get("Cookie")) # name="val="
await sess.close()

asyncio.run(req())

i updated the reproduce section to contain a full example

@Dreamsorcerer Dreamsorcerer removed the needs-info Issue is lacking sufficient information and will be closed if not provided label Sep 29, 2024
@Cycloctane
Copy link
Contributor

ClientSession()._request() creates a temporary CookieJar tmp_cookie_jar to handle the cookies from the request() parameters. This tmp_cookie_jar only uses default (quote_cookie=True).

aiohttp/aiohttp/client.py

Lines 576 to 583 in 24b0e6f

all_cookies = self._cookie_jar.filter_cookies(url)
if cookies is not None:
tmp_cookie_jar = CookieJar()
tmp_cookie_jar.update_cookies(cookies)
req_cookies = tmp_cookie_jar.filter_cookies(url)
if req_cookies:
all_cookies.load(req_cookies)

If cookies are directly passed to the manually created CookieJar, they will remain unquoted.

import aiohttp
import asyncio

async def req():
    tcp_conn = aiohttp.TCPConnector(limit=10, force_close=True)
    c_jar = aiohttp.CookieJar(quote_cookie=False)
    sess = aiohttp.ClientSession(connector=tcp_conn, cookie_jar=c_jar)
    cookies = {"name": "val="}
    c_jar.update_cookies(cookies)
    resp = await sess.request(url="http://localhost:8000/", method="GET")
    print(resp.request_info.headers.get("Cookie")) # name=val=
    await sess.close()

asyncio.run(req())

@Dreamsorcerer
Copy link
Member

So, perhaps we should be reusing the settings from the global CookieJar. Think you could turn that into a full test?

Cycloctane added a commit to Cycloctane/aiohttp that referenced this issue Oct 4, 2024
Cycloctane added a commit to Cycloctane/aiohttp that referenced this issue Oct 4, 2024
Cycloctane added a commit to Cycloctane/aiohttp that referenced this issue Oct 4, 2024
Cycloctane added a commit to Cycloctane/aiohttp that referenced this issue Oct 4, 2024
Dreamsorcerer pushed a commit that referenced this issue Oct 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants