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

Side by Side Diff: swarm_client/third_party/requests/sessions.py

Issue 69143004: Delete swarm_client. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/
Patch Set: Created 7 years, 1 month 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 requests.session
5 ~~~~~~~~~~~~~~~~
6
7 This module provides a Session object to manage and persist settings across
8 requests (cookies, auth, proxies).
9
10 """
11 import os
12 from collections import Mapping
13 from datetime import datetime
14
15 from .compat import cookielib, OrderedDict, urljoin, urlparse
16 from .cookies import cookiejar_from_dict, extract_cookies_to_jar, RequestsCookie Jar
17 from .models import Request, PreparedRequest
18 from .hooks import default_hooks, dispatch_hook
19 from .utils import to_key_val_list, default_headers
20 from .exceptions import TooManyRedirects, InvalidSchema
21 from .structures import CaseInsensitiveDict
22
23 from .adapters import HTTPAdapter
24
25 from .utils import requote_uri, get_environ_proxies, get_netrc_auth
26
27 from .status_codes import codes
28 REDIRECT_STATI = (
29 codes.moved, # 301
30 codes.found, # 302
31 codes.other, # 303
32 codes.temporary_moved, # 307
33 )
34 DEFAULT_REDIRECT_LIMIT = 30
35
36
37 def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
38 """
39 Determines appropriate setting for a given request, taking into account the
40 explicit setting on that request, and the setting in the session. If a
41 setting is a dictionary, they will be merged together using `dict_class`
42 """
43
44 if session_setting is None:
45 return request_setting
46
47 if request_setting is None:
48 return session_setting
49
50 # Bypass if not a dictionary (e.g. verify)
51 if not (
52 isinstance(session_setting, Mapping) and
53 isinstance(request_setting, Mapping)
54 ):
55 return request_setting
56
57 merged_setting = dict_class(to_key_val_list(session_setting))
58 merged_setting.update(to_key_val_list(request_setting))
59
60 # Remove keys that are set to None.
61 for (k, v) in request_setting.items():
62 if v is None:
63 del merged_setting[k]
64
65 return merged_setting
66
67
68 class SessionRedirectMixin(object):
69 def resolve_redirects(self, resp, req, stream=False, timeout=None,
70 verify=True, cert=None, proxies=None):
71 """Receives a Response. Returns a generator of Responses."""
72
73 i = 0
74
75 # ((resp.status_code is codes.see_other))
76 while (('location' in resp.headers and resp.status_code in REDIRECT_STAT I)):
77 prepared_request = req.copy()
78
79 resp.content # Consume socket so it can be released
80
81 if i >= self.max_redirects:
82 raise TooManyRedirects('Exceeded %s redirects.' % self.max_redir ects)
83
84 # Release the connection back into the pool.
85 resp.close()
86
87 url = resp.headers['location']
88 method = req.method
89
90 # Handle redirection without scheme (see: RFC 1808 Section 4)
91 if url.startswith('//'):
92 parsed_rurl = urlparse(resp.url)
93 url = '%s:%s' % (parsed_rurl.scheme, url)
94
95 # The scheme should be lower case...
96 if '://' in url:
97 scheme, uri = url.split('://', 1)
98 url = '%s://%s' % (scheme.lower(), uri)
99
100 # Facilitate non-RFC2616-compliant 'location' headers
101 # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/re source')
102 # Compliant with RFC3986, we percent encode the url.
103 if not urlparse(url).netloc:
104 url = urljoin(resp.url, requote_uri(url))
105 else:
106 url = requote_uri(url)
107
108 prepared_request.url = url
109
110 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
111 if (resp.status_code == codes.see_other and
112 method != 'HEAD'):
113 method = 'GET'
114
115 # Do what the browsers do, despite standards...
116 if (resp.status_code in (codes.moved, codes.found) and
117 method not in ('GET', 'HEAD')):
118 method = 'GET'
119
120 prepared_request.method = method
121
122 # https://github.com/kennethreitz/requests/issues/1084
123 if resp.status_code not in (codes.temporary, codes.resume):
124 if 'Content-Length' in prepared_request.headers:
125 del prepared_request.headers['Content-Length']
126
127 prepared_request.body = None
128
129 headers = prepared_request.headers
130 try:
131 del headers['Cookie']
132 except KeyError:
133 pass
134
135 prepared_request.prepare_cookies(self.cookies)
136
137 resp = self.send(
138 prepared_request,
139 stream=stream,
140 timeout=timeout,
141 verify=verify,
142 cert=cert,
143 proxies=proxies,
144 allow_redirects=False,
145 )
146
147 extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)
148
149 i += 1
150 yield resp
151
152
153 class Session(SessionRedirectMixin):
154 """A Requests session.
155
156 Provides cookie persistence, connection-pooling, and configuration.
157
158 Basic Usage::
159
160 >>> import requests
161 >>> s = requests.Session()
162 >>> s.get('http://httpbin.org/get')
163 200
164 """
165
166 __attrs__ = [
167 'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks',
168 'params', 'verify', 'cert', 'prefetch', 'adapters', 'stream',
169 'trust_env', 'max_redirects']
170
171 def __init__(self):
172
173 #: A case-insensitive dictionary of headers to be sent on each
174 #: :class:`Request <Request>` sent from this
175 #: :class:`Session <Session>`.
176 self.headers = default_headers()
177
178 #: Default Authentication tuple or object to attach to
179 #: :class:`Request <Request>`.
180 self.auth = None
181
182 #: Dictionary mapping protocol to the URL of the proxy (e.g.
183 #: {'http': 'foo.bar:3128'}) to be used on each
184 #: :class:`Request <Request>`.
185 self.proxies = {}
186
187 #: Event-handling hooks.
188 self.hooks = default_hooks()
189
190 #: Dictionary of querystring data to attach to each
191 #: :class:`Request <Request>`. The dictionary values may be lists for
192 #: representing multivalued query parameters.
193 self.params = {}
194
195 #: Stream response content default.
196 self.stream = False
197
198 #: SSL Verification default.
199 self.verify = True
200
201 #: SSL certificate default.
202 self.cert = None
203
204 #: Maximum number of redirects allowed. If the request exceeds this
205 #: limit, a :class:`TooManyRedirects` exception is raised.
206 self.max_redirects = DEFAULT_REDIRECT_LIMIT
207
208 #: Should we trust the environment?
209 self.trust_env = True
210
211 #: A CookieJar containing all currently outstanding cookies set on this
212 #: session. By default it is a
213 #: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but
214 #: may be any other ``cookielib.CookieJar`` compatible object.
215 self.cookies = cookiejar_from_dict({})
216
217 # Default connection adapters.
218 self.adapters = OrderedDict()
219 self.mount('https://', HTTPAdapter())
220 self.mount('http://', HTTPAdapter())
221
222 def __enter__(self):
223 return self
224
225 def __exit__(self, *args):
226 self.close()
227
228 def prepare_request(self, request):
229 """Constructs a :class:`PreparedRequest <PreparedRequest>` for
230 transmission and returns it. The :class:`PreparedRequest` has settings
231 merged from the :class:`Request <Request>` instance and those of the
232 :class:`Session`.
233
234 :param request: :class:`Request` instance to prepare with this
235 session's settings.
236 """
237 cookies = request.cookies or {}
238
239 # Bootstrap CookieJar.
240 if not isinstance(cookies, cookielib.CookieJar):
241 cookies = cookiejar_from_dict(cookies)
242
243 # Merge with session cookies
244 merged_cookies = RequestsCookieJar()
245 merged_cookies.update(self.cookies)
246 merged_cookies.update(cookies)
247
248
249 # Set environment's basic authentication if not explicitly set.
250 auth = request.auth
251 if self.trust_env and not auth and not self.auth:
252 auth = get_netrc_auth(request.url)
253
254 p = PreparedRequest()
255 p.prepare(
256 method=request.method.upper(),
257 url=request.url,
258 files=request.files,
259 data=request.data,
260 headers=merge_setting(request.headers, self.headers, dict_class=Case InsensitiveDict),
261 params=merge_setting(request.params, self.params),
262 auth=merge_setting(auth, self.auth),
263 cookies=merged_cookies,
264 hooks=merge_setting(request.hooks, self.hooks),
265 )
266 return p
267
268 def request(self, method, url,
269 params=None,
270 data=None,
271 headers=None,
272 cookies=None,
273 files=None,
274 auth=None,
275 timeout=None,
276 allow_redirects=True,
277 proxies=None,
278 hooks=None,
279 stream=None,
280 verify=None,
281 cert=None):
282 """Constructs a :class:`Request <Request>`, prepares it and sends it.
283 Returns :class:`Response <Response>` object.
284
285 :param method: method for the new :class:`Request` object.
286 :param url: URL for the new :class:`Request` object.
287 :param params: (optional) Dictionary or bytes to be sent in the query
288 string for the :class:`Request`.
289 :param data: (optional) Dictionary or bytes to send in the body of the
290 :class:`Request`.
291 :param headers: (optional) Dictionary of HTTP Headers to send with the
292 :class:`Request`.
293 :param cookies: (optional) Dict or CookieJar object to send with the
294 :class:`Request`.
295 :param files: (optional) Dictionary of 'filename': file-like-objects
296 for multipart encoding upload.
297 :param auth: (optional) Auth tuple or callable to enable
298 Basic/Digest/Custom HTTP Auth.
299 :param timeout: (optional) Float describing the timeout of the
300 request.
301 :param allow_redirects: (optional) Boolean. Set to True by default.
302 :param proxies: (optional) Dictionary mapping protocol to the URL of
303 the proxy.
304 :param stream: (optional) whether to immediately download the response
305 content. Defaults to ``False``.
306 :param verify: (optional) if ``True``, the SSL cert will be verified.
307 A CA_BUNDLE path can also be provided.
308 :param cert: (optional) if String, path to ssl client cert file (.pem).
309 If Tuple, ('cert', 'key') pair.
310 """
311 # Create the Request.
312 req = Request(
313 method = method.upper(),
314 url = url,
315 headers = headers,
316 files = files,
317 data = data or {},
318 params = params or {},
319 auth = auth,
320 cookies = cookies,
321 hooks = hooks,
322 )
323 prep = self.prepare_request(req)
324
325 proxies = proxies or {}
326
327 # Gather clues from the surrounding environment.
328 if self.trust_env:
329 # Set environment's proxies.
330 env_proxies = get_environ_proxies(url) or {}
331 for (k, v) in env_proxies.items():
332 proxies.setdefault(k, v)
333
334 # Look for configuration.
335 if not verify and verify is not False:
336 verify = os.environ.get('REQUESTS_CA_BUNDLE')
337
338 # Curl compatibility.
339 if not verify and verify is not False:
340 verify = os.environ.get('CURL_CA_BUNDLE')
341
342 # Merge all the kwargs.
343 proxies = merge_setting(proxies, self.proxies)
344 stream = merge_setting(stream, self.stream)
345 verify = merge_setting(verify, self.verify)
346 cert = merge_setting(cert, self.cert)
347
348 # Send the request.
349 send_kwargs = {
350 'stream': stream,
351 'timeout': timeout,
352 'verify': verify,
353 'cert': cert,
354 'proxies': proxies,
355 'allow_redirects': allow_redirects,
356 }
357 resp = self.send(prep, **send_kwargs)
358
359 return resp
360
361 def get(self, url, **kwargs):
362 """Sends a GET request. Returns :class:`Response` object.
363
364 :param url: URL for the new :class:`Request` object.
365 :param \*\*kwargs: Optional arguments that ``request`` takes.
366 """
367
368 kwargs.setdefault('allow_redirects', True)
369 return self.request('GET', url, **kwargs)
370
371 def options(self, url, **kwargs):
372 """Sends a OPTIONS request. Returns :class:`Response` object.
373
374 :param url: URL for the new :class:`Request` object.
375 :param \*\*kwargs: Optional arguments that ``request`` takes.
376 """
377
378 kwargs.setdefault('allow_redirects', True)
379 return self.request('OPTIONS', url, **kwargs)
380
381 def head(self, url, **kwargs):
382 """Sends a HEAD request. Returns :class:`Response` object.
383
384 :param url: URL for the new :class:`Request` object.
385 :param \*\*kwargs: Optional arguments that ``request`` takes.
386 """
387
388 kwargs.setdefault('allow_redirects', False)
389 return self.request('HEAD', url, **kwargs)
390
391 def post(self, url, data=None, **kwargs):
392 """Sends a POST request. Returns :class:`Response` object.
393
394 :param url: URL for the new :class:`Request` object.
395 :param data: (optional) Dictionary, bytes, or file-like object to send i n the body of the :class:`Request`.
396 :param \*\*kwargs: Optional arguments that ``request`` takes.
397 """
398
399 return self.request('POST', url, data=data, **kwargs)
400
401 def put(self, url, data=None, **kwargs):
402 """Sends a PUT request. Returns :class:`Response` object.
403
404 :param url: URL for the new :class:`Request` object.
405 :param data: (optional) Dictionary, bytes, or file-like object to send i n the body of the :class:`Request`.
406 :param \*\*kwargs: Optional arguments that ``request`` takes.
407 """
408
409 return self.request('PUT', url, data=data, **kwargs)
410
411 def patch(self, url, data=None, **kwargs):
412 """Sends a PATCH request. Returns :class:`Response` object.
413
414 :param url: URL for the new :class:`Request` object.
415 :param data: (optional) Dictionary, bytes, or file-like object to send i n the body of the :class:`Request`.
416 :param \*\*kwargs: Optional arguments that ``request`` takes.
417 """
418
419 return self.request('PATCH', url, data=data, **kwargs)
420
421 def delete(self, url, **kwargs):
422 """Sends a DELETE request. Returns :class:`Response` object.
423
424 :param url: URL for the new :class:`Request` object.
425 :param \*\*kwargs: Optional arguments that ``request`` takes.
426 """
427
428 return self.request('DELETE', url, **kwargs)
429
430 def send(self, request, **kwargs):
431 """Send a given PreparedRequest."""
432 # Set defaults that the hooks can utilize to ensure they always have
433 # the correct parameters to reproduce the previous request.
434 kwargs.setdefault('stream', self.stream)
435 kwargs.setdefault('verify', self.verify)
436 kwargs.setdefault('cert', self.cert)
437 kwargs.setdefault('proxies', self.proxies)
438
439 # It's possible that users might accidentally send a Request object.
440 # Guard against that specific failure case.
441 if not isinstance(request, PreparedRequest):
442 raise ValueError('You can only send PreparedRequests.')
443
444 # Set up variables needed for resolve_redirects and dispatching of
445 # hooks
446 allow_redirects = kwargs.pop('allow_redirects', True)
447 stream = kwargs.get('stream')
448 timeout = kwargs.get('timeout')
449 verify = kwargs.get('verify')
450 cert = kwargs.get('cert')
451 proxies = kwargs.get('proxies')
452 hooks = request.hooks
453
454 # Get the appropriate adapter to use
455 adapter = self.get_adapter(url=request.url)
456
457 # Start time (approximately) of the request
458 start = datetime.utcnow()
459 # Send the request
460 r = adapter.send(request, **kwargs)
461 # Total elapsed time of the request (approximately)
462 r.elapsed = datetime.utcnow() - start
463
464 # Response manipulation hooks
465 r = dispatch_hook('response', hooks, r, **kwargs)
466
467 # Persist cookies
468 if r.history:
469 # If the hooks create history then we want those cookies too
470 for resp in r.history:
471 extract_cookies_to_jar(self.cookies, resp.request, resp.raw)
472 extract_cookies_to_jar(self.cookies, request, r.raw)
473
474 # Redirect resolving generator.
475 gen = self.resolve_redirects(r, request, stream=stream,
476 timeout=timeout, verify=verify, cert=cert,
477 proxies=proxies)
478
479 # Resolve redirects if allowed.
480 history = [resp for resp in gen] if allow_redirects else []
481
482 # Shuffle things around if there's history.
483 if history:
484 # Insert the first (original) request at the start
485 history.insert(0, r)
486 # Get the last request made
487 r = history.pop()
488 r.history = tuple(history)
489
490 return r
491
492 def get_adapter(self, url):
493 """Returns the appropriate connnection adapter for the given URL."""
494 for (prefix, adapter) in self.adapters.items():
495
496 if url.lower().startswith(prefix):
497 return adapter
498
499 # Nothing matches :-/
500 raise InvalidSchema("No connection adapters were found for '%s'" % url)
501
502 def close(self):
503 """Closes all adapters and as such the session"""
504 for v in self.adapters.values():
505 v.close()
506
507 def mount(self, prefix, adapter):
508 """Registers a connection adapter to a prefix.
509
510 Adapters are sorted in descending order by key length."""
511 self.adapters[prefix] = adapter
512 keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
513 for key in keys_to_move:
514 self.adapters[key] = self.adapters.pop(key)
515
516 def __getstate__(self):
517 return dict((attr, getattr(self, attr, None)) for attr in self.__attrs__ )
518
519 def __setstate__(self, state):
520 for attr, value in state.items():
521 setattr(self, attr, value)
522
523
524 def session():
525 """Returns a :class:`Session` for context-management."""
526
527 return Session()
OLDNEW
« no previous file with comments | « swarm_client/third_party/requests/packages/urllib3/util.py ('k') | swarm_client/third_party/requests/status_codes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698