0001 """Load / save to libwww-perl (LWP) format files. 0002 0003 Actually, the format is slightly extended from that used by LWP's 0004 (libwww-perl's) HTTP::Cookies, to avoid losing some RFC 2965 information 0005 not recorded by LWP. 0006 0007 It uses the version string "2.0", though really there isn't an LWP Cookies 0008 2.0 format. This indicates that there is extra information in here 0009 (domain_dot and # port_spec) while still being compatible with 0010 libwww-perl, I hope. 0011 0012 """ 0013 0014 import time, re, logging 0015 from cookielib import (reraise_unmasked_exceptions, FileCookieJar, Cookie, 0016 MISSING_FILENAME_TEXT, join_header_words, split_header_words, 0017 iso2time, time2isoz) 0018 0019 def lwp_cookie_str(cookie): 0020 """Return string representation of Cookie in an the LWP cookie file format. 0021 0022 Actually, the format is extended a bit -- see module docstring. 0023 0024 """ 0025 h = [(cookie.name, cookie.value), 0026 ("path", cookie.path), 0027 ("domain", cookie.domain)] 0028 if cookie.port is not None: h.append(("port", cookie.port)) 0029 if cookie.path_specified: h.append(("path_spec", None)) 0030 if cookie.port_specified: h.append(("port_spec", None)) 0031 if cookie.domain_initial_dot: h.append(("domain_dot", None)) 0032 if cookie.secure: h.append(("secure", None)) 0033 if cookie.expires: h.append(("expires", 0034 time2isoz(float(cookie.expires)))) 0035 if cookie.discard: h.append(("discard", None)) 0036 if cookie.comment: h.append(("comment", cookie.comment)) 0037 if cookie.comment_url: h.append(("commenturl", cookie.comment_url)) 0038 0039 keys = cookie._rest.keys() 0040 keys.sort() 0041 for k in keys: 0042 h.append((k, str(cookie._rest[k]))) 0043 0044 h.append(("version", str(cookie.version))) 0045 0046 return join_header_words([h]) 0047 0048 class LWPCookieJar(FileCookieJar): 0049 """ 0050 The LWPCookieJar saves a sequence of"Set-Cookie3" lines. 0051 "Set-Cookie3" is the format used by the libwww-perl libary, not known 0052 to be compatible with any browser, but which is easy to read and 0053 doesn't lose information about RFC 2965 cookies. 0054 0055 Additional methods 0056 0057 as_lwp_str(ignore_discard=True, ignore_expired=True) 0058 0059 """ 0060 0061 def as_lwp_str(self, ignore_discard=True, ignore_expires=True): 0062 """Return cookies as a string of "\n"-separated "Set-Cookie3" headers. 0063 0064 ignore_discard and ignore_expires: see docstring for FileCookieJar.save 0065 0066 """ 0067 now = time.time() 0068 r = [] 0069 for cookie in self: 0070 if not ignore_discard and cookie.discard: 0071 continue 0072 if not ignore_expires and cookie.is_expired(now): 0073 continue 0074 r.append("Set-Cookie3: %s" % lwp_cookie_str(cookie)) 0075 return "\n".join(r+[""]) 0076 0077 def save(self, filename=None, ignore_discard=False, ignore_expires=False): 0078 if filename is None: 0079 if self.filename is not None: filename = self.filename 0080 else: raise ValueError(MISSING_FILENAME_TEXT) 0081 0082 f = open(filename, "w") 0083 try: 0084 # There really isn't an LWP Cookies 2.0 format, but this indicates 0085 # that there is extra information in here (domain_dot and 0086 # port_spec) while still being compatible with libwww-perl, I hope. 0087 f.write("#LWP-Cookies-2.0\n") 0088 f.write(self.as_lwp_str(ignore_discard, ignore_expires)) 0089 finally: 0090 f.close() 0091 0092 def _really_load(self, f, filename, ignore_discard, ignore_expires): 0093 magic = f.readline() 0094 if not re.search(self.magic_re, magic): 0095 msg = "%s does not seem to contain cookies" % filename 0096 raise IOError(msg) 0097 0098 now = time.time() 0099 0100 header = "Set-Cookie3:" 0101 boolean_attrs = ("port_spec", "path_spec", "domain_dot", 0102 "secure", "discard") 0103 value_attrs = ("version", 0104 "port", "path", "domain", 0105 "expires", 0106 "comment", "commenturl") 0107 0108 try: 0109 while 1: 0110 line = f.readline() 0111 if line == "": break 0112 if not line.startswith(header): 0113 continue 0114 line = line[len(header):].strip() 0115 0116 for data in split_header_words([line]): 0117 name, value = data[0] 0118 # name and value are an exception here, since a plain "foo" 0119 # (with no "=", unlike "bar=foo") means a cookie with no 0120 # name and value "foo". With all other cookie-attributes, 0121 # the situation is reversed: "foo" means an attribute named 0122 # "foo" with no value! 0123 if value is None: 0124 name, value = value, name 0125 standard = {} 0126 rest = {} 0127 for k in boolean_attrs: 0128 standard[k] = False 0129 for k, v in data[1:]: 0130 if k is not None: 0131 lc = k.lower() 0132 else: 0133 lc = None 0134 # don't lose case distinction for unknown fields 0135 if (lc in value_attrs) or (lc in boolean_attrs): 0136 k = lc 0137 if k in boolean_attrs: 0138 if v is None: v = True 0139 standard[k] = v 0140 elif k in value_attrs: 0141 standard[k] = v 0142 else: 0143 rest[k] = v 0144 0145 h = standard.get 0146 expires = h("expires") 0147 discard = h("discard") 0148 if expires is not None: 0149 expires = iso2time(expires) 0150 if expires is None: 0151 discard = True 0152 domain = h("domain") 0153 domain_specified = domain.startswith(".") 0154 c = Cookie(h("version"), name, value, 0155 h("port"), h("port_spec"), 0156 domain, domain_specified, h("domain_dot"), 0157 h("path"), h("path_spec"), 0158 h("secure"), 0159 expires, 0160 discard, 0161 h("comment"), 0162 h("commenturl"), 0163 rest) 0164 if not ignore_discard and c.discard: 0165 continue 0166 if not ignore_expires and c.is_expired(now): 0167 continue 0168 self.set_cookie(c) 0169 except: 0170 reraise_unmasked_exceptions((IOError,)) 0171 raise IOError("invalid Set-Cookie3 format file %s" % filename) 0172
Generated by PyXR 0.9.4