Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/requests/cookies.py
811 views
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
550
551