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
Bug report
Bug description:
SUMMARY:
http.cookiejar.CookieJardoes 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 whenCookieJar.extract_cookies()is called with a response that tries to expire the cookie, the cookie will not be removed, sinceCookieJar._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 thathttp.cookiejarcode is not correctly ignoring it. I think the simplest fix is forCookieJar._cookie_from_cookie_tuple()to callself.clear()twice, once with a domain with a leading period and once without a leading period.Here's an example using
httpx:Here's an example using only standard library modules:
CPython versions tested on:
3.10, 3.11
Operating systems tested on:
Linux, Windows