0001 """Mozilla / Netscape cookie loading / saving.""" 0002 0003 import re, time, logging 0004 0005 from cookielib import (reraise_unmasked_exceptions, FileCookieJar, Cookie, 0006 MISSING_FILENAME_TEXT) 0007 0008 class MozillaCookieJar(FileCookieJar): 0009 """ 0010 0011 WARNING: you may want to backup your browser's cookies file if you use 0012 this class to save cookies. I *think* it works, but there have been 0013 bugs in the past! 0014 0015 This class differs from CookieJar only in the format it uses to save and 0016 load cookies to and from a file. This class uses the Mozilla/Netscape 0017 `cookies.txt' format. lynx uses this file format, too. 0018 0019 Don't expect cookies saved while the browser is running to be noticed by 0020 the browser (in fact, Mozilla on unix will overwrite your saved cookies if 0021 you change them on disk while it's running; on Windows, you probably can't 0022 save at all while the browser is running). 0023 0024 Note that the Mozilla/Netscape format will downgrade RFC2965 cookies to 0025 Netscape cookies on saving. 0026 0027 In particular, the cookie version and port number information is lost, 0028 together with information about whether or not Path, Port and Discard were 0029 specified by the Set-Cookie2 (or Set-Cookie) header, and whether or not the 0030 domain as set in the HTTP header started with a dot (yes, I'm aware some 0031 domains in Netscape files start with a dot and some don't -- trust me, you 0032 really don't want to know any more about this). 0033 0034 Note that though Mozilla and Netscape use the same format, they use 0035 slightly different headers. The class saves cookies using the Netscape 0036 header by default (Mozilla can cope with that). 0037 0038 """ 0039 magic_re = "#( Netscape)? HTTP Cookie File" 0040 header = """\ 0041 # Netscape HTTP Cookie File 0042 # http://www.netscape.com/newsref/std/cookie_spec.html 0043 # This is a generated file! Do not edit. 0044 0045 """ 0046 0047 def _really_load(self, f, filename, ignore_discard, ignore_expires): 0048 now = time.time() 0049 0050 magic = f.readline() 0051 if not re.search(self.magic_re, magic): 0052 f.close() 0053 raise IOError( 0054 "%s does not look like a Netscape format cookies file" % 0055 filename) 0056 0057 try: 0058 while 1: 0059 line = f.readline() 0060 if line == "": break 0061 0062 # last field may be absent, so keep any trailing tab 0063 if line.endswith("\n"): line = line[:-1] 0064 0065 # skip comments and blank lines XXX what is $ for? 0066 if (line.strip().startswith("#") or 0067 line.strip().startswith("$") or 0068 line.strip() == ""): 0069 continue 0070 0071 domain, domain_specified, path, secure, expires, name, value = \ 0072 line.split("\t") 0073 secure = (secure == "TRUE") 0074 domain_specified = (domain_specified == "TRUE") 0075 if name == "": 0076 name = value 0077 value = None 0078 0079 initial_dot = domain.startswith(".") 0080 assert domain_specified == initial_dot 0081 0082 discard = False 0083 if expires == "": 0084 expires = None 0085 discard = True 0086 0087 # assume path_specified is false 0088 c = Cookie(0, name, value, 0089 None, False, 0090 domain, domain_specified, initial_dot, 0091 path, False, 0092 secure, 0093 expires, 0094 discard, 0095 None, 0096 None, 0097 {}) 0098 if not ignore_discard and c.discard: 0099 continue 0100 if not ignore_expires and c.is_expired(now): 0101 continue 0102 self.set_cookie(c) 0103 0104 except: 0105 reraise_unmasked_exceptions((IOError,)) 0106 raise IOError("invalid Netscape format file %s: %s" % 0107 (filename, line)) 0108 0109 def save(self, filename=None, ignore_discard=False, ignore_expires=False): 0110 if filename is None: 0111 if self.filename is not None: filename = self.filename 0112 else: raise ValueError(MISSING_FILENAME_TEXT) 0113 0114 f = open(filename, "w") 0115 try: 0116 f.write(self.header) 0117 now = time.time() 0118 for cookie in self: 0119 if not ignore_discard and cookie.discard: 0120 continue 0121 if not ignore_expires and cookie.is_expired(now): 0122 continue 0123 if cookie.secure: secure = "TRUE" 0124 else: secure = "FALSE" 0125 if cookie.domain.startswith("."): initial_dot = "TRUE" 0126 else: initial_dot = "FALSE" 0127 if cookie.expires is not None: 0128 expires = str(cookie.expires) 0129 else: 0130 expires = "" 0131 if cookie.value is None: 0132 # cookies.txt regards 'Set-Cookie: foo' as a cookie 0133 # with no name, whereas cookielib regards it as a 0134 # cookie with no value. 0135 name = "" 0136 value = cookie.name 0137 else: 0138 name = cookie.name 0139 value = cookie.value 0140 f.write( 0141 "\t".join([cookie.domain, initial_dot, cookie.path, 0142 secure, expires, name, value])+ 0143 "\n") 0144 finally: 0145 f.close() 0146
Generated by PyXR 0.9.4