Mercurial > repos > guerler > springsuite
comparison planemo/lib/python3.7/site-packages/requests/cookies.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
| author | guerler |
|---|---|
| date | Fri, 31 Jul 2020 00:32:28 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:d30785e31577 | 1:56ad4e20f292 |
|---|---|
| 1 # -*- coding: utf-8 -*- | |
| 2 | |
| 3 """ | |
| 4 requests.cookies | |
| 5 ~~~~~~~~~~~~~~~~ | |
| 6 | |
| 7 Compatibility code to be able to use `cookielib.CookieJar` with requests. | |
| 8 | |
| 9 requests.utils imports from here, so be careful with imports. | |
| 10 """ | |
| 11 | |
| 12 import copy | |
| 13 import time | |
| 14 import calendar | |
| 15 | |
| 16 from ._internal_utils import to_native_string | |
| 17 from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping | |
| 18 | |
| 19 try: | |
| 20 import threading | |
| 21 except ImportError: | |
| 22 import dummy_threading as threading | |
| 23 | |
| 24 | |
| 25 class MockRequest(object): | |
| 26 """Wraps a `requests.Request` to mimic a `urllib2.Request`. | |
| 27 | |
| 28 The code in `cookielib.CookieJar` expects this interface in order to correctly | |
| 29 manage cookie policies, i.e., determine whether a cookie can be set, given the | |
| 30 domains of the request and the cookie. | |
| 31 | |
| 32 The original request object is read-only. The client is responsible for collecting | |
| 33 the new headers via `get_new_headers()` and interpreting them appropriately. You | |
| 34 probably want `get_cookie_header`, defined below. | |
| 35 """ | |
| 36 | |
| 37 def __init__(self, request): | |
| 38 self._r = request | |
| 39 self._new_headers = {} | |
| 40 self.type = urlparse(self._r.url).scheme | |
| 41 | |
| 42 def get_type(self): | |
| 43 return self.type | |
| 44 | |
| 45 def get_host(self): | |
| 46 return urlparse(self._r.url).netloc | |
| 47 | |
| 48 def get_origin_req_host(self): | |
| 49 return self.get_host() | |
| 50 | |
| 51 def get_full_url(self): | |
| 52 # Only return the response's URL if the user hadn't set the Host | |
| 53 # header | |
| 54 if not self._r.headers.get('Host'): | |
| 55 return self._r.url | |
| 56 # If they did set it, retrieve it and reconstruct the expected domain | |
| 57 host = to_native_string(self._r.headers['Host'], encoding='utf-8') | |
| 58 parsed = urlparse(self._r.url) | |
| 59 # Reconstruct the URL as we expect it | |
| 60 return urlunparse([ | |
| 61 parsed.scheme, host, parsed.path, parsed.params, parsed.query, | |
| 62 parsed.fragment | |
| 63 ]) | |
| 64 | |
| 65 def is_unverifiable(self): | |
| 66 return True | |
| 67 | |
| 68 def has_header(self, name): | |
| 69 return name in self._r.headers or name in self._new_headers | |
| 70 | |
| 71 def get_header(self, name, default=None): | |
| 72 return self._r.headers.get(name, self._new_headers.get(name, default)) | |
| 73 | |
| 74 def add_header(self, key, val): | |
| 75 """cookielib has no legitimate use for this method; add it back if you find one.""" | |
| 76 raise NotImplementedError("Cookie headers should be added with add_unredirected_header()") | |
| 77 | |
| 78 def add_unredirected_header(self, name, value): | |
| 79 self._new_headers[name] = value | |
| 80 | |
| 81 def get_new_headers(self): | |
| 82 return self._new_headers | |
| 83 | |
| 84 @property | |
| 85 def unverifiable(self): | |
| 86 return self.is_unverifiable() | |
| 87 | |
| 88 @property | |
| 89 def origin_req_host(self): | |
| 90 return self.get_origin_req_host() | |
| 91 | |
| 92 @property | |
| 93 def host(self): | |
| 94 return self.get_host() | |
| 95 | |
| 96 | |
| 97 class MockResponse(object): | |
| 98 """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. | |
| 99 | |
| 100 ...what? Basically, expose the parsed HTTP headers from the server response | |
| 101 the way `cookielib` expects to see them. | |
| 102 """ | |
| 103 | |
| 104 def __init__(self, headers): | |
| 105 """Make a MockResponse for `cookielib` to read. | |
| 106 | |
| 107 :param headers: a httplib.HTTPMessage or analogous carrying the headers | |
| 108 """ | |
| 109 self._headers = headers | |
| 110 | |
| 111 def info(self): | |
| 112 return self._headers | |
| 113 | |
| 114 def getheaders(self, name): | |
| 115 self._headers.getheaders(name) | |
| 116 | |
| 117 | |
| 118 def extract_cookies_to_jar(jar, request, response): | |
| 119 """Extract the cookies from the response into a CookieJar. | |
| 120 | |
| 121 :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar) | |
| 122 :param request: our own requests.Request object | |
| 123 :param response: urllib3.HTTPResponse object | |
| 124 """ | |
| 125 if not (hasattr(response, '_original_response') and | |
| 126 response._original_response): | |
| 127 return | |
| 128 # the _original_response field is the wrapped httplib.HTTPResponse object, | |
| 129 req = MockRequest(request) | |
| 130 # pull out the HTTPMessage with the headers and put it in the mock: | |
| 131 res = MockResponse(response._original_response.msg) | |
| 132 jar.extract_cookies(res, req) | |
| 133 | |
| 134 | |
| 135 def get_cookie_header(jar, request): | |
| 136 """ | |
| 137 Produce an appropriate Cookie header string to be sent with `request`, or None. | |
| 138 | |
| 139 :rtype: str | |
| 140 """ | |
| 141 r = MockRequest(request) | |
| 142 jar.add_cookie_header(r) | |
| 143 return r.get_new_headers().get('Cookie') | |
| 144 | |
| 145 | |
| 146 def remove_cookie_by_name(cookiejar, name, domain=None, path=None): | |
| 147 """Unsets a cookie by name, by default over all domains and paths. | |
| 148 | |
| 149 Wraps CookieJar.clear(), is O(n). | |
| 150 """ | |
| 151 clearables = [] | |
| 152 for cookie in cookiejar: | |
| 153 if cookie.name != name: | |
| 154 continue | |
| 155 if domain is not None and domain != cookie.domain: | |
| 156 continue | |
| 157 if path is not None and path != cookie.path: | |
| 158 continue | |
| 159 clearables.append((cookie.domain, cookie.path, cookie.name)) | |
| 160 | |
| 161 for domain, path, name in clearables: | |
| 162 cookiejar.clear(domain, path, name) | |
| 163 | |
| 164 | |
| 165 class CookieConflictError(RuntimeError): | |
| 166 """There are two cookies that meet the criteria specified in the cookie jar. | |
| 167 Use .get and .set and include domain and path args in order to be more specific. | |
| 168 """ | |
| 169 | |
| 170 | |
| 171 class RequestsCookieJar(cookielib.CookieJar, MutableMapping): | |
| 172 """Compatibility class; is a cookielib.CookieJar, but exposes a dict | |
| 173 interface. | |
| 174 | |
| 175 This is the CookieJar we create by default for requests and sessions that | |
| 176 don't specify one, since some clients may expect response.cookies and | |
| 177 session.cookies to support dict operations. | |
| 178 | |
| 179 Requests does not use the dict interface internally; it's just for | |
| 180 compatibility with external client code. All requests code should work | |
| 181 out of the box with externally provided instances of ``CookieJar``, e.g. | |
| 182 ``LWPCookieJar`` and ``FileCookieJar``. | |
| 183 | |
| 184 Unlike a regular CookieJar, this class is pickleable. | |
| 185 | |
| 186 .. warning:: dictionary operations that are normally O(1) may be O(n). | |
| 187 """ | |
| 188 | |
| 189 def get(self, name, default=None, domain=None, path=None): | |
| 190 """Dict-like get() that also supports optional domain and path args in | |
| 191 order to resolve naming collisions from using one cookie jar over | |
| 192 multiple domains. | |
| 193 | |
| 194 .. warning:: operation is O(n), not O(1). | |
| 195 """ | |
| 196 try: | |
| 197 return self._find_no_duplicates(name, domain, path) | |
| 198 except KeyError: | |
| 199 return default | |
| 200 | |
| 201 def set(self, name, value, **kwargs): | |
| 202 """Dict-like set() that also supports optional domain and path args in | |
| 203 order to resolve naming collisions from using one cookie jar over | |
| 204 multiple domains. | |
| 205 """ | |
| 206 # support client code that unsets cookies by assignment of a None value: | |
| 207 if value is None: | |
| 208 remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path')) | |
| 209 return | |
| 210 | |
| 211 if isinstance(value, Morsel): | |
| 212 c = morsel_to_cookie(value) | |
| 213 else: | |
| 214 c = create_cookie(name, value, **kwargs) | |
| 215 self.set_cookie(c) | |
| 216 return c | |
| 217 | |
| 218 def iterkeys(self): | |
| 219 """Dict-like iterkeys() that returns an iterator of names of cookies | |
| 220 from the jar. | |
| 221 | |
| 222 .. seealso:: itervalues() and iteritems(). | |
| 223 """ | |
| 224 for cookie in iter(self): | |
| 225 yield cookie.name | |
| 226 | |
| 227 def keys(self): | |
| 228 """Dict-like keys() that returns a list of names of cookies from the | |
| 229 jar. | |
| 230 | |
| 231 .. seealso:: values() and items(). | |
| 232 """ | |
| 233 return list(self.iterkeys()) | |
| 234 | |
| 235 def itervalues(self): | |
| 236 """Dict-like itervalues() that returns an iterator of values of cookies | |
| 237 from the jar. | |
| 238 | |
| 239 .. seealso:: iterkeys() and iteritems(). | |
| 240 """ | |
| 241 for cookie in iter(self): | |
| 242 yield cookie.value | |
| 243 | |
| 244 def values(self): | |
| 245 """Dict-like values() that returns a list of values of cookies from the | |
| 246 jar. | |
| 247 | |
| 248 .. seealso:: keys() and items(). | |
| 249 """ | |
| 250 return list(self.itervalues()) | |
| 251 | |
| 252 def iteritems(self): | |
| 253 """Dict-like iteritems() that returns an iterator of name-value tuples | |
| 254 from the jar. | |
| 255 | |
| 256 .. seealso:: iterkeys() and itervalues(). | |
| 257 """ | |
| 258 for cookie in iter(self): | |
| 259 yield cookie.name, cookie.value | |
| 260 | |
| 261 def items(self): | |
| 262 """Dict-like items() that returns a list of name-value tuples from the | |
| 263 jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a | |
| 264 vanilla python dict of key value pairs. | |
| 265 | |
| 266 .. seealso:: keys() and values(). | |
| 267 """ | |
| 268 return list(self.iteritems()) | |
| 269 | |
| 270 def list_domains(self): | |
| 271 """Utility method to list all the domains in the jar.""" | |
| 272 domains = [] | |
| 273 for cookie in iter(self): | |
| 274 if cookie.domain not in domains: | |
| 275 domains.append(cookie.domain) | |
| 276 return domains | |
| 277 | |
| 278 def list_paths(self): | |
| 279 """Utility method to list all the paths in the jar.""" | |
| 280 paths = [] | |
| 281 for cookie in iter(self): | |
| 282 if cookie.path not in paths: | |
| 283 paths.append(cookie.path) | |
| 284 return paths | |
| 285 | |
| 286 def multiple_domains(self): | |
| 287 """Returns True if there are multiple domains in the jar. | |
| 288 Returns False otherwise. | |
| 289 | |
| 290 :rtype: bool | |
| 291 """ | |
| 292 domains = [] | |
| 293 for cookie in iter(self): | |
| 294 if cookie.domain is not None and cookie.domain in domains: | |
| 295 return True | |
| 296 domains.append(cookie.domain) | |
| 297 return False # there is only one domain in jar | |
| 298 | |
| 299 def get_dict(self, domain=None, path=None): | |
| 300 """Takes as an argument an optional domain and path and returns a plain | |
| 301 old Python dict of name-value pairs of cookies that meet the | |
| 302 requirements. | |
| 303 | |
| 304 :rtype: dict | |
| 305 """ | |
| 306 dictionary = {} | |
| 307 for cookie in iter(self): | |
| 308 if ( | |
| 309 (domain is None or cookie.domain == domain) and | |
| 310 (path is None or cookie.path == path) | |
| 311 ): | |
| 312 dictionary[cookie.name] = cookie.value | |
| 313 return dictionary | |
| 314 | |
| 315 def __contains__(self, name): | |
| 316 try: | |
| 317 return super(RequestsCookieJar, self).__contains__(name) | |
| 318 except CookieConflictError: | |
| 319 return True | |
| 320 | |
| 321 def __getitem__(self, name): | |
| 322 """Dict-like __getitem__() for compatibility with client code. Throws | |
| 323 exception if there are more than one cookie with name. In that case, | |
| 324 use the more explicit get() method instead. | |
| 325 | |
| 326 .. warning:: operation is O(n), not O(1). | |
| 327 """ | |
| 328 return self._find_no_duplicates(name) | |
| 329 | |
| 330 def __setitem__(self, name, value): | |
| 331 """Dict-like __setitem__ for compatibility with client code. Throws | |
| 332 exception if there is already a cookie of that name in the jar. In that | |
| 333 case, use the more explicit set() method instead. | |
| 334 """ | |
| 335 self.set(name, value) | |
| 336 | |
| 337 def __delitem__(self, name): | |
| 338 """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s | |
| 339 ``remove_cookie_by_name()``. | |
| 340 """ | |
| 341 remove_cookie_by_name(self, name) | |
| 342 | |
| 343 def set_cookie(self, cookie, *args, **kwargs): | |
| 344 if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'): | |
| 345 cookie.value = cookie.value.replace('\\"', '') | |
| 346 return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs) | |
| 347 | |
| 348 def update(self, other): | |
| 349 """Updates this jar with cookies from another CookieJar or dict-like""" | |
| 350 if isinstance(other, cookielib.CookieJar): | |
| 351 for cookie in other: | |
| 352 self.set_cookie(copy.copy(cookie)) | |
| 353 else: | |
| 354 super(RequestsCookieJar, self).update(other) | |
| 355 | |
| 356 def _find(self, name, domain=None, path=None): | |
| 357 """Requests uses this method internally to get cookie values. | |
| 358 | |
| 359 If there are conflicting cookies, _find arbitrarily chooses one. | |
| 360 See _find_no_duplicates if you want an exception thrown if there are | |
| 361 conflicting cookies. | |
| 362 | |
| 363 :param name: a string containing name of cookie | |
| 364 :param domain: (optional) string containing domain of cookie | |
| 365 :param path: (optional) string containing path of cookie | |
| 366 :return: cookie.value | |
| 367 """ | |
| 368 for cookie in iter(self): | |
| 369 if cookie.name == name: | |
| 370 if domain is None or cookie.domain == domain: | |
| 371 if path is None or cookie.path == path: | |
| 372 return cookie.value | |
| 373 | |
| 374 raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) | |
| 375 | |
| 376 def _find_no_duplicates(self, name, domain=None, path=None): | |
| 377 """Both ``__get_item__`` and ``get`` call this function: it's never | |
| 378 used elsewhere in Requests. | |
| 379 | |
| 380 :param name: a string containing name of cookie | |
| 381 :param domain: (optional) string containing domain of cookie | |
| 382 :param path: (optional) string containing path of cookie | |
| 383 :raises KeyError: if cookie is not found | |
| 384 :raises CookieConflictError: if there are multiple cookies | |
| 385 that match name and optionally domain and path | |
| 386 :return: cookie.value | |
| 387 """ | |
| 388 toReturn = None | |
| 389 for cookie in iter(self): | |
| 390 if cookie.name == name: | |
| 391 if domain is None or cookie.domain == domain: | |
| 392 if path is None or cookie.path == path: | |
| 393 if toReturn is not None: # if there are multiple cookies that meet passed in criteria | |
| 394 raise CookieConflictError('There are multiple cookies with name, %r' % (name)) | |
| 395 toReturn = cookie.value # we will eventually return this as long as no cookie conflict | |
| 396 | |
| 397 if toReturn: | |
| 398 return toReturn | |
| 399 raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) | |
| 400 | |
| 401 def __getstate__(self): | |
| 402 """Unlike a normal CookieJar, this class is pickleable.""" | |
| 403 state = self.__dict__.copy() | |
| 404 # remove the unpickleable RLock object | |
| 405 state.pop('_cookies_lock') | |
| 406 return state | |
| 407 | |
| 408 def __setstate__(self, state): | |
| 409 """Unlike a normal CookieJar, this class is pickleable.""" | |
| 410 self.__dict__.update(state) | |
| 411 if '_cookies_lock' not in self.__dict__: | |
| 412 self._cookies_lock = threading.RLock() | |
| 413 | |
| 414 def copy(self): | |
| 415 """Return a copy of this RequestsCookieJar.""" | |
| 416 new_cj = RequestsCookieJar() | |
| 417 new_cj.set_policy(self.get_policy()) | |
| 418 new_cj.update(self) | |
| 419 return new_cj | |
| 420 | |
| 421 def get_policy(self): | |
| 422 """Return the CookiePolicy instance used.""" | |
| 423 return self._policy | |
| 424 | |
| 425 | |
| 426 def _copy_cookie_jar(jar): | |
| 427 if jar is None: | |
| 428 return None | |
| 429 | |
| 430 if hasattr(jar, 'copy'): | |
| 431 # We're dealing with an instance of RequestsCookieJar | |
| 432 return jar.copy() | |
| 433 # We're dealing with a generic CookieJar instance | |
| 434 new_jar = copy.copy(jar) | |
| 435 new_jar.clear() | |
| 436 for cookie in jar: | |
| 437 new_jar.set_cookie(copy.copy(cookie)) | |
| 438 return new_jar | |
| 439 | |
| 440 | |
| 441 def create_cookie(name, value, **kwargs): | |
| 442 """Make a cookie from underspecified parameters. | |
| 443 | |
| 444 By default, the pair of `name` and `value` will be set for the domain '' | |
| 445 and sent on every request (this is sometimes called a "supercookie"). | |
| 446 """ | |
| 447 result = { | |
| 448 'version': 0, | |
| 449 'name': name, | |
| 450 'value': value, | |
| 451 'port': None, | |
| 452 'domain': '', | |
| 453 'path': '/', | |
| 454 'secure': False, | |
| 455 'expires': None, | |
| 456 'discard': True, | |
| 457 'comment': None, | |
| 458 'comment_url': None, | |
| 459 'rest': {'HttpOnly': None}, | |
| 460 'rfc2109': False, | |
| 461 } | |
| 462 | |
| 463 badargs = set(kwargs) - set(result) | |
| 464 if badargs: | |
| 465 err = 'create_cookie() got unexpected keyword arguments: %s' | |
| 466 raise TypeError(err % list(badargs)) | |
| 467 | |
| 468 result.update(kwargs) | |
| 469 result['port_specified'] = bool(result['port']) | |
| 470 result['domain_specified'] = bool(result['domain']) | |
| 471 result['domain_initial_dot'] = result['domain'].startswith('.') | |
| 472 result['path_specified'] = bool(result['path']) | |
| 473 | |
| 474 return cookielib.Cookie(**result) | |
| 475 | |
| 476 | |
| 477 def morsel_to_cookie(morsel): | |
| 478 """Convert a Morsel object into a Cookie containing the one k/v pair.""" | |
| 479 | |
| 480 expires = None | |
| 481 if morsel['max-age']: | |
| 482 try: | |
| 483 expires = int(time.time() + int(morsel['max-age'])) | |
| 484 except ValueError: | |
| 485 raise TypeError('max-age: %s must be integer' % morsel['max-age']) | |
| 486 elif morsel['expires']: | |
| 487 time_template = '%a, %d-%b-%Y %H:%M:%S GMT' | |
| 488 expires = calendar.timegm( | |
| 489 time.strptime(morsel['expires'], time_template) | |
| 490 ) | |
| 491 return create_cookie( | |
| 492 comment=morsel['comment'], | |
| 493 comment_url=bool(morsel['comment']), | |
| 494 discard=False, | |
| 495 domain=morsel['domain'], | |
| 496 expires=expires, | |
| 497 name=morsel.key, | |
| 498 path=morsel['path'], | |
| 499 port=None, | |
| 500 rest={'HttpOnly': morsel['httponly']}, | |
| 501 rfc2109=False, | |
| 502 secure=bool(morsel['secure']), | |
| 503 value=morsel.value, | |
| 504 version=morsel['version'] or 0, | |
| 505 ) | |
| 506 | |
| 507 | |
| 508 def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): | |
| 509 """Returns a CookieJar from a key/value dictionary. | |
| 510 | |
| 511 :param cookie_dict: Dict of key/values to insert into CookieJar. | |
| 512 :param cookiejar: (optional) A cookiejar to add the cookies to. | |
| 513 :param overwrite: (optional) If False, will not replace cookies | |
| 514 already in the jar with new ones. | |
| 515 :rtype: CookieJar | |
| 516 """ | |
| 517 if cookiejar is None: | |
| 518 cookiejar = RequestsCookieJar() | |
| 519 | |
| 520 if cookie_dict is not None: | |
| 521 names_from_jar = [cookie.name for cookie in cookiejar] | |
| 522 for name in cookie_dict: | |
| 523 if overwrite or (name not in names_from_jar): | |
| 524 cookiejar.set_cookie(create_cookie(name, cookie_dict[name])) | |
| 525 | |
| 526 return cookiejar | |
| 527 | |
| 528 | |
| 529 def merge_cookies(cookiejar, cookies): | |
| 530 """Add cookies to cookiejar and returns a merged CookieJar. | |
| 531 | |
| 532 :param cookiejar: CookieJar object to add the cookies to. | |
| 533 :param cookies: Dictionary or CookieJar object to be added. | |
| 534 :rtype: CookieJar | |
| 535 """ | |
| 536 if not isinstance(cookiejar, cookielib.CookieJar): | |
| 537 raise ValueError('You can only merge into CookieJar') | |
| 538 | |
| 539 if isinstance(cookies, dict): | |
| 540 cookiejar = cookiejar_from_dict( | |
| 541 cookies, cookiejar=cookiejar, overwrite=False) | |
| 542 elif isinstance(cookies, cookielib.CookieJar): | |
| 543 try: | |
| 544 cookiejar.update(cookies) | |
| 545 except AttributeError: | |
| 546 for cookie_in_jar in cookies: | |
| 547 cookiejar.set_cookie(cookie_in_jar) | |
| 548 | |
| 549 return cookiejar |
