Note that though Mozilla and Netscape use the same format, they use
slightly different headers. The class saves cookies using the Netscape
header by default (Mozilla can cope with that).
magic_re = re.compile("#( Netscape)? HTTP Cookie File")
# Netscape HTTP Cookie File
# http://curl.haxx.se/rfc/cookie_spec.html
# This is a generated file! Do not edit.
def _really_load(self, f, filename, ignore_discard, ignore_expires):
if not self.magic_re.search(magic):
"%r does not look like a Netscape format cookies file" %
# last field may be absent, so keep any trailing tab
if line.endswith("\n"): line = line[:-1]
# skip comments and blank lines XXX what is $ for?
if (line.strip().startswith(("#", "$")) or
domain, domain_specified, path, secure, expires, name, value = \
secure = (secure == "TRUE")
domain_specified = (domain_specified == "TRUE")
# cookies.txt regards 'Set-Cookie: foo' as a cookie
# with no name, whereas http.cookiejar regards it as a
initial_dot = domain.startswith(".")
assert domain_specified == initial_dot
# assume path_specified is false
c = Cookie(0, name, value,
domain, domain_specified, initial_dot,
if not ignore_discard and c.discard:
if not ignore_expires and c.is_expired(now):
_warn_unhandled_exception()
raise LoadError("invalid Netscape format cookies file %r: %r" %
def save(self, filename=None, ignore_discard=False, ignore_expires=False):
if self.filename is not None: filename = self.filename
else: raise ValueError(MISSING_FILENAME_TEXT)
with open(filename, "w") as f:
if not ignore_discard and cookie.discard:
if not ignore_expires and cookie.is_expired(now):
if cookie.secure: secure = "TRUE"
if cookie.domain.startswith("."): initial_dot = "TRUE"
else: initial_dot = "FALSE"
if cookie.expires is not None:
expires = str(cookie.expires)
# cookies.txt regards 'Set-Cookie: foo' as a cookie
# with no name, whereas http.cookiejar regards it as a
"\t".join([cookie.domain, initial_dot, cookie.path,
secure, expires, name, value])+