%PDF- %PDF-
Direktori : /lib/python3/dist-packages/mechanize/ |
Current File : //lib/python3/dist-packages/mechanize/_clientcookie.py |
from __future__ import absolute_import import re import time from .polyglot import ( Cookie as _Cookie, CookieJar as CJ, MozillaCookieJar as MCJ, request_host as request_host_lc, DEFAULT_HTTP_PORT, CookiePolicy, DefaultCookiePolicy, FileCookieJar, LoadError, LWPCookieJar, _debug, domain_match, eff_request_host, escape_path, is_HDN, lwp_cookie_str, reach, request_path, request_port, user_domain_match, iteritems) __all__ = [ 'DEFAULT_HTTP_PORT', 'CookiePolicy', 'DefaultCookiePolicy', 'request_host_lc', 'MozillaCookieJar', 'escape_path', 'is_HDN', 'request_port', 'LWPCookieJar', 'LoadError', 'reach', 'FileCookieJar', 'lwp_cookie_str', 'domain_match', 'request_path', 'user_domain_match' ] def effective_request_host(request): """Return the effective request-host, as defined by RFC 2965.""" return eff_request_host(request)[1] def request_is_unverifiable(request): try: return request.is_unverifiable() except AttributeError: if hasattr(request, "unverifiable"): return request.unverifiable else: raise def cookies_equal(a, b): return all(getattr(a, x) == getattr(b, x) for x in Cookie._attrs) class Cookie(_Cookie): _attrs = ("version", "name", "value", "port", "port_specified", "domain", "domain_specified", "domain_initial_dot", "path", "path_specified", "secure", "expires", "discard", "comment", "comment_url", "rfc2109", "_rest") def __eq__(self, other): return all(getattr(self, a) == getattr(other, a) for a in self._attrs) def __ne__(self, other): return not (self == other) class CookieJar(CJ): def __getstate__(self): ans = self.__dict__.copy() del ans['_cookies_lock'] return ans def __setstate__(self, val): for k, v in iteritems(val): setattr(self, k, v) def cookies_for_request(self, request): """Return a list of cookies to be returned to server. The returned list of cookie instances is sorted in the order they should appear in the Cookie: header for return to the server. See add_cookie_header.__doc__ for the interface required of the request argument. """ with self._cookies_lock: self._policy._now = self._now = int(time.time()) cookies = self._cookies_for_request(request) # add cookies in order of most specific (i.e. longest) path first def key(x): return len(x.path) cookies.sort(key=key, reverse=True) return cookies def get_policy(self): return self._policy def _normalized_cookie_tuples(self, attrs_set): """Return list of tuples containing normalised cookie information. attrs_set is the list of lists of key,value pairs extracted from the Set-Cookie or Set-Cookie2 headers. Tuples are name, value, standard, rest, where name and value are the cookie name and value, standard is a dictionary containing the standard cookie-attributes (discard, secure, version, expires or max-age, domain, path and port) and rest is a dictionary containing the rest of the cookie-attributes. """ cookie_tuples = [] boolean_attrs = "discard", "secure" value_attrs = ("version", "expires", "max-age", "domain", "path", "port", "comment", "commenturl") for cookie_attrs in attrs_set: name, value = cookie_attrs[0] # Build dictionary of standard cookie-attributes (standard) and # dictionary of other cookie-attributes (rest). # Note: expiry time is normalised to seconds since epoch. V0 # cookies should have the Expires cookie-attribute, and V1 cookies # should have Max-Age, but since V1 includes RFC 2109 cookies (and # since V0 cookies may be a mish-mash of Netscape and RFC 2109), we # accept either (but prefer Max-Age). max_age_set = False bad_cookie = False standard = {} rest = {} for k, v in cookie_attrs[1:]: lc = k.lower() # don't lose case distinction for unknown fields if lc in value_attrs or lc in boolean_attrs: k = lc if k in boolean_attrs and v is None: # boolean cookie-attribute is present, but has no value # (like "discard", rather than "port=80") v = True if k in standard: # only first value is significant continue if k == "domain": if v is None: _debug(" missing value for domain attribute") bad_cookie = True break # RFC 2965 section 3.3.3 v = v.lower() if k == "expires": if max_age_set: # Prefer max-age to expires (like Mozilla) continue if v is None: _debug(" missing or invalid value for expires " "attribute: treating as session cookie") continue if k == "max-age": max_age_set = True try: v = int(v) except ValueError: _debug(" missing or invalid (non-numeric) value for " "max-age attribute") bad_cookie = True break # convert RFC 2965 Max-Age to seconds since epoch # XXX Strictly you're supposed to follow RFC 2616 # age-calculation rules. Remember that zero Max-Age # is a request to discard (old and new) cookie, though. k = "expires" v = self._now + v if not v and k == 'path': # Added by Kovid, not in stdlib implementation v = '/' if (k in value_attrs) or (k in boolean_attrs): if (v is None and k not in ("port", "comment", "commenturl")): _debug(" missing value for %s attribute" % k) bad_cookie = True break standard[k] = v else: rest[k] = v if bad_cookie: continue cookie_tuples.append((name, value, standard, rest)) return cookie_tuples def __getitem__(self, i): for q, ans in enumerate(self): if q == i: return ans raise IndexError() try: from http.cookiejar import NETSCAPE_MAGIC_RGX, NETSCAPE_HEADER_TEXT except ImportError: # python < 3.10 NETSCAPE_MAGIC_RGX = MCJ.magic_re NETSCAPE_HEADER_TEXT = MCJ.header else: MCJ.header = NETSCAPE_HEADER_TEXT # needed for tests class MozillaCookieJar(MCJ): def _really_load(self, f, filename, ignore_discard, ignore_expires): now = time.time() magic = f.readline() if not re.search(NETSCAPE_MAGIC_RGX, magic): f.close() raise LoadError( "%r does not look like a Netscape format cookies file" % filename) try: while 1: line = f.readline() if line == "": break # 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 line.strip() == ""): continue (domain, domain_specified, path, secure, expires, name, value) = line.split("\t", 6) # Changed by Kovid secure = (secure == "TRUE") domain_specified = (domain_specified == "TRUE") if name == "": # cookies.txt regards 'Set-Cookie: foo' as a cookie # with no name, whereas cookielib regards it as a # cookie with no value. name = value value = None initial_dot = domain.startswith(".") if domain_specified != initial_dot: raise ValueError() assert domain_specified == initial_dot discard = False if expires == "": expires = None discard = True # assume path_specified is false c = Cookie(0, name, value, None, False, domain, domain_specified, initial_dot, path, False, secure, expires, discard, None, None, {}) if not ignore_discard and c.discard: continue if not ignore_expires and c.is_expired(now): continue self.set_cookie(c) except IOError: raise except Exception: raise LoadError("invalid Netscape format cookies file %r: %r" % (filename, line))