Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: third_party/requests/cookies.py

Issue 24076010: Add 'requests' library to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- coding: utf-8 -*-
2
3 """
4 Compatibility code to be able to use `cookielib.CookieJar` with requests.
5
6 requests.utils imports from here, so be careful with imports.
7 """
8
9 import collections
10 from .compat import cookielib, urlparse, Morsel
11
12 try:
13 import threading
14 # grr, pyflakes: this fixes "redefinition of unused 'threading'"
15 threading
16 except ImportError:
17 import dummy_threading as threading
18
19
20 class MockRequest(object):
21 """Wraps a `requests.Request` to mimic a `urllib2.Request`.
22
23 The code in `cookielib.CookieJar` expects this interface in order to correct ly
24 manage cookie policies, i.e., determine whether a cookie can be set, given t he
25 domains of the request and the cookie.
26
27 The original request object is read-only. The client is responsible for coll ecting
28 the new headers via `get_new_headers()` and interpreting them appropriately. You
29 probably want `get_cookie_header`, defined below.
30 """
31
32 def __init__(self, request):
33 self._r = request
34 self._new_headers = {}
35 self.type = urlparse(self._r.url).scheme
36
37 def get_type(self):
38 return self.type
39
40 def get_host(self):
41 return urlparse(self._r.url).netloc
42
43 def get_origin_req_host(self):
44 return self.get_host()
45
46 def get_full_url(self):
47 return self._r.url
48
49 def is_unverifiable(self):
50 return True
51
52 def has_header(self, name):
53 return name in self._r.headers or name in self._new_headers
54
55 def get_header(self, name, default=None):
56 return self._r.headers.get(name, self._new_headers.get(name, default))
57
58 def add_header(self, key, val):
59 """cookielib has no legitimate use for this method; add it back if you f ind one."""
60 raise NotImplementedError("Cookie headers should be added with add_unred irected_header()")
61
62 def add_unredirected_header(self, name, value):
63 self._new_headers[name] = value
64
65 def get_new_headers(self):
66 return self._new_headers
67
68 @property
69 def unverifiable(self):
70 return self.is_unverifiable()
71
72 @property
73 def origin_req_host(self):
74 return self.get_origin_req_host()
75
76
77 class MockResponse(object):
78 """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
79
80 ...what? Basically, expose the parsed HTTP headers from the server response
81 the way `cookielib` expects to see them.
82 """
83
84 def __init__(self, headers):
85 """Make a MockResponse for `cookielib` to read.
86
87 :param headers: a httplib.HTTPMessage or analogous carrying the headers
88 """
89 self._headers = headers
90
91 def info(self):
92 return self._headers
93
94 def getheaders(self, name):
95 self._headers.getheaders(name)
96
97
98 def extract_cookies_to_jar(jar, request, response):
99 """Extract the cookies from the response into a CookieJar.
100
101 :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar)
102 :param request: our own requests.Request object
103 :param response: urllib3.HTTPResponse object
104 """
105 # the _original_response field is the wrapped httplib.HTTPResponse object,
106 req = MockRequest(request)
107 # pull out the HTTPMessage with the headers and put it in the mock:
108 res = MockResponse(response._original_response.msg)
109 jar.extract_cookies(res, req)
110
111
112 def get_cookie_header(jar, request):
113 """Produce an appropriate Cookie header string to be sent with `request`, or None."""
114 r = MockRequest(request)
115 jar.add_cookie_header(r)
116 return r.get_new_headers().get('Cookie')
117
118
119 def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
120 """Unsets a cookie by name, by default over all domains and paths.
121
122 Wraps CookieJar.clear(), is O(n).
123 """
124 clearables = []
125 for cookie in cookiejar:
126 if cookie.name == name:
127 if domain is None or domain == cookie.domain:
128 if path is None or path == cookie.path:
129 clearables.append((cookie.domain, cookie.path, cookie.name))
130
131 for domain, path, name in clearables:
132 cookiejar.clear(domain, path, name)
133
134
135 class CookieConflictError(RuntimeError):
136 """There are two cookies that meet the criteria specified in the cookie jar.
137 Use .get and .set and include domain and path args in order to be more speci fic."""
138
139
140 class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
141 """Compatibility class; is a cookielib.CookieJar, but exposes a dict interfa ce.
142
143 This is the CookieJar we create by default for requests and sessions that
144 don't specify one, since some clients may expect response.cookies and
145 session.cookies to support dict operations.
146
147 Don't use the dict interface internally; it's just for compatibility with
148 with external client code. All `requests` code should work out of the box
149 with externally provided instances of CookieJar, e.g., LWPCookieJar and
150 FileCookieJar.
151
152 Caution: dictionary operations that are normally O(1) may be O(n).
153
154 Unlike a regular CookieJar, this class is pickleable.
155 """
156
157 def get(self, name, default=None, domain=None, path=None):
158 """Dict-like get() that also supports optional domain and path args in
159 order to resolve naming collisions from using one cookie jar over
160 multiple domains. Caution: operation is O(n), not O(1)."""
161 try:
162 return self._find_no_duplicates(name, domain, path)
163 except KeyError:
164 return default
165
166 def set(self, name, value, **kwargs):
167 """Dict-like set() that also supports optional domain and path args in
168 order to resolve naming collisions from using one cookie jar over
169 multiple domains."""
170 # support client code that unsets cookies by assignment of a None value:
171 if value is None:
172 remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path= kwargs.get('path'))
173 return
174
175 if isinstance(value, Morsel):
176 c = morsel_to_cookie(value)
177 else:
178 c = create_cookie(name, value, **kwargs)
179 self.set_cookie(c)
180 return c
181
182 def keys(self):
183 """Dict-like keys() that returns a list of names of cookies from the jar .
184 See values() and items()."""
185 keys = []
186 for cookie in iter(self):
187 keys.append(cookie.name)
188 return keys
189
190 def values(self):
191 """Dict-like values() that returns a list of values of cookies from the jar.
192 See keys() and items()."""
193 values = []
194 for cookie in iter(self):
195 values.append(cookie.value)
196 return values
197
198 def items(self):
199 """Dict-like items() that returns a list of name-value tuples from the j ar.
200 See keys() and values(). Allows client-code to call "dict(RequestsCookie Jar)
201 and get a vanilla python dict of key value pairs."""
202 items = []
203 for cookie in iter(self):
204 items.append((cookie.name, cookie.value))
205 return items
206
207 def list_domains(self):
208 """Utility method to list all the domains in the jar."""
209 domains = []
210 for cookie in iter(self):
211 if cookie.domain not in domains:
212 domains.append(cookie.domain)
213 return domains
214
215 def list_paths(self):
216 """Utility method to list all the paths in the jar."""
217 paths = []
218 for cookie in iter(self):
219 if cookie.path not in paths:
220 paths.append(cookie.path)
221 return paths
222
223 def multiple_domains(self):
224 """Returns True if there are multiple domains in the jar.
225 Returns False otherwise."""
226 domains = []
227 for cookie in iter(self):
228 if cookie.domain is not None and cookie.domain in domains:
229 return True
230 domains.append(cookie.domain)
231 return False # there is only one domain in jar
232
233 def get_dict(self, domain=None, path=None):
234 """Takes as an argument an optional domain and path and returns a plain old
235 Python dict of name-value pairs of cookies that meet the requirements."" "
236 dictionary = {}
237 for cookie in iter(self):
238 if (domain is None or cookie.domain == domain) and (path is None
239 or cookie.path == path):
240 dictionary[cookie.name] = cookie.value
241 return dictionary
242
243 def __getitem__(self, name):
244 """Dict-like __getitem__() for compatibility with client code. Throws ex ception
245 if there are more than one cookie with name. In that case, use the more
246 explicit get() method instead. Caution: operation is O(n), not O(1)."""
247
248 return self._find_no_duplicates(name)
249
250 def __setitem__(self, name, value):
251 """Dict-like __setitem__ for compatibility with client code. Throws exce ption
252 if there is already a cookie of that name in the jar. In that case, use the more
253 explicit set() method instead."""
254
255 self.set(name, value)
256
257 def __delitem__(self, name):
258 """Deletes a cookie given a name. Wraps cookielib.CookieJar's remove_coo kie_by_name()."""
259 remove_cookie_by_name(self, name)
260
261 def update(self, other):
262 """Updates this jar with cookies from another CookieJar or dict-like"""
263 if isinstance(other, cookielib.CookieJar):
264 for cookie in other:
265 self.set_cookie(cookie)
266 else:
267 super(RequestsCookieJar, self).update(other)
268
269 def _find(self, name, domain=None, path=None):
270 """Requests uses this method internally to get cookie values. Takes as a rgs name
271 and optional domain and path. Returns a cookie.value. If there are confl icting cookies,
272 _find arbitrarily chooses one. See _find_no_duplicates if you want an ex ception thrown
273 if there are conflicting cookies."""
274 for cookie in iter(self):
275 if cookie.name == name:
276 if domain is None or cookie.domain == domain:
277 if path is None or cookie.path == path:
278 return cookie.value
279
280 raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
281
282 def _find_no_duplicates(self, name, domain=None, path=None):
283 """__get_item__ and get call _find_no_duplicates -- never used in Reques ts internally.
284 Takes as args name and optional domain and path. Returns a cookie.value.
285 Throws KeyError if cookie is not found and CookieConflictError if there are
286 multiple cookies that match name and optionally domain and path."""
287 toReturn = None
288 for cookie in iter(self):
289 if cookie.name == name:
290 if domain is None or cookie.domain == domain:
291 if path is None or cookie.path == path:
292 if toReturn is not None: # if there are multiple cookie s that meet passed in criteria
293 raise CookieConflictError('There are multiple cookie s with name, %r' % (name))
294 toReturn = cookie.value # we will eventually return thi s as long as no cookie conflict
295
296 if toReturn:
297 return toReturn
298 raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
299
300 def __getstate__(self):
301 """Unlike a normal CookieJar, this class is pickleable."""
302 state = self.__dict__.copy()
303 # remove the unpickleable RLock object
304 state.pop('_cookies_lock')
305 return state
306
307 def __setstate__(self, state):
308 """Unlike a normal CookieJar, this class is pickleable."""
309 self.__dict__.update(state)
310 if '_cookies_lock' not in self.__dict__:
311 self._cookies_lock = threading.RLock()
312
313 def copy(self):
314 """Return a copy of this RequestsCookieJar."""
315 new_cj = RequestsCookieJar()
316 new_cj.update(self)
317 return new_cj
318
319
320 def create_cookie(name, value, **kwargs):
321 """Make a cookie from underspecified parameters.
322
323 By default, the pair of `name` and `value` will be set for the domain ''
324 and sent on every request (this is sometimes called a "supercookie").
325 """
326 result = dict(
327 version=0,
328 name=name,
329 value=value,
330 port=None,
331 domain='',
332 path='/',
333 secure=False,
334 expires=None,
335 discard=True,
336 comment=None,
337 comment_url=None,
338 rest={'HttpOnly': None},
339 rfc2109=False,)
340
341 badargs = set(kwargs) - set(result)
342 if badargs:
343 err = 'create_cookie() got unexpected keyword arguments: %s'
344 raise TypeError(err % list(badargs))
345
346 result.update(kwargs)
347 result['port_specified'] = bool(result['port'])
348 result['domain_specified'] = bool(result['domain'])
349 result['domain_initial_dot'] = result['domain'].startswith('.')
350 result['path_specified'] = bool(result['path'])
351
352 return cookielib.Cookie(**result)
353
354
355 def morsel_to_cookie(morsel):
356 """Convert a Morsel object into a Cookie containing the one k/v pair."""
357 c = create_cookie(
358 name=morsel.key,
359 value=morsel.value,
360 version=morsel['version'] or 0,
361 port=None,
362 port_specified=False,
363 domain=morsel['domain'],
364 domain_specified=bool(morsel['domain']),
365 domain_initial_dot=morsel['domain'].startswith('.'),
366 path=morsel['path'],
367 path_specified=bool(morsel['path']),
368 secure=bool(morsel['secure']),
369 expires=morsel['max-age'] or morsel['expires'],
370 discard=False,
371 comment=morsel['comment'],
372 comment_url=bool(morsel['comment']),
373 rest={'HttpOnly': morsel['httponly']},
374 rfc2109=False,)
375 return c
376
377
378 def cookiejar_from_dict(cookie_dict, cookiejar=None):
379 """Returns a CookieJar from a key/value dictionary.
380
381 :param cookie_dict: Dict of key/values to insert into CookieJar.
382 """
383 if cookiejar is None:
384 cookiejar = RequestsCookieJar()
385
386 if cookie_dict is not None:
387 for name in cookie_dict:
388 cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
389 return cookiejar
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698