Skip to content

CookieJar.extract_cookies() does not clear expired cookies set with a domain #108931

@ppena-LiveData

Description

@ppena-LiveData

Bug report

Bug description:

SUMMARY: http.cookiejar.CookieJar does not delete expired cookies with a domain unless the domain name has a leading period.

DETAILS: If CookieJar.set_cookie() is given a cookie that specifies a domain, then when CookieJar.extract_cookies() is called with a response that tries to expire the cookie, the cookie will not be removed, since CookieJar._cookie_from_cookie_tuple() is prepending a period to the domain name and only attempting to clear a cookie with a domain with a leading period. RFC 6265 Section 4.1.2.3 says, "a leading %x2E ("."), if present, is ignored," but that http.cookiejar code is not correctly ignoring it. I think the simplest fix is for CookieJar._cookie_from_cookie_tuple() to call self.clear() twice, once with a domain with a leading period and once without a leading period.

Here's an example using httpx:

import asyncio
import httpx
from aiohttp import web

COOKIE = 'TestCookie'
DOMAIN = 'localhost'
PORT = 8088

async def handler(request):
    rsp = web.Response(text='OK')
    rsp.del_cookie(COOKIE, domain=DOMAIN)
    return rsp

async def server():
    server = web.Server(handler)
    runner = web.ServerRunner(server)
    await runner.setup()
    site = web.TCPSite(runner, DOMAIN, PORT)
    await site.start()

async def httpx_client():
    async with httpx.AsyncClient(timeout=100_000) as client:
        client.cookies.set(COOKIE, 'deprecated', domain=DOMAIN)
        print(client.cookies.jar)
        await client.get(f'http://{DOMAIN}:{PORT}')
        print(client.cookies.jar)

async def main():
    await server()
    await httpx_client()

asyncio.run(main())

Here's an example using only standard library modules:

import email.message
import urllib.request, urllib.response
from http.cookiejar import Cookie, CookieJar

COOKIE = 'TestCookie'
DOMAIN = 'localhost'
PORT = 8088

jar = CookieJar()
cookie = Cookie(comment=None, comment_url=None, discard=True, domain=DOMAIN,
    domain_initial_dot=False, domain_specified=True, expires=None,
    name=COOKIE, path='/', path_specified=True, port=None, port_specified=False,
    rest={'HttpOnly': None}, secure=False, value='deprecated', version=0
)
jar.set_cookie(cookie)
print(jar)

host = f'{DOMAIN}:{PORT}'
req = urllib.request.Request(f'http://{host}', headers={'Host': host})
expires = 'expires=Thu, 01 Jan 1970 00:00:00 GMT'
resp_headers = {
    'content-length': '2',
    'content-type': 'text/plain; charset=utf-8',
    'date': 'Tue, 05 Sep 2023 12:38:18 GMT',
    'server': 'Python/3.10 aiohttp/3.8.5',
    'set-cookie': f'TestCookie=""; Domain={DOMAIN}; {expires}; Max-Age=0; Path=/'
}
headers = email.message.Message()
for key, val in resp_headers.items():
    headers[key] = val
resp = urllib.response.addinfourl(fp=None, url=f'http://{host}', headers=headers)

jar.extract_cookies(resp, req)
print(jar)

CPython versions tested on:

3.10, 3.11

Operating systems tested on:

Linux, Windows

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions