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

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

Issue 25004007: Update 'requests' lib to v2.0. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: Created 7 years, 2 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
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 2
3 """ 3 """
4 requests.session 4 requests.session
5 ~~~~~~~~~~~~~~~~ 5 ~~~~~~~~~~~~~~~~
6 6
7 This module provides a Session object to manage and persist settings across 7 This module provides a Session object to manage and persist settings across
8 requests (cookies, auth, proxies). 8 requests (cookies, auth, proxies).
9 9
10 """ 10 """
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 64
65 return merged_setting 65 return merged_setting
66 66
67 67
68 class SessionRedirectMixin(object): 68 class SessionRedirectMixin(object):
69 def resolve_redirects(self, resp, req, stream=False, timeout=None, 69 def resolve_redirects(self, resp, req, stream=False, timeout=None,
70 verify=True, cert=None, proxies=None): 70 verify=True, cert=None, proxies=None):
71 """Receives a Response. Returns a generator of Responses.""" 71 """Receives a Response. Returns a generator of Responses."""
72 72
73 i = 0 73 i = 0
74 prepared_request = PreparedRequest()
75 prepared_request.body = req.body
76 prepared_request.headers = req.headers.copy()
77 prepared_request.hooks = req.hooks
78 prepared_request.method = req.method
79 prepared_request.url = req.url
80 74
81 # ((resp.status_code is codes.see_other)) 75 # ((resp.status_code is codes.see_other))
82 while (('location' in resp.headers and resp.status_code in REDIRECT_STAT I)): 76 while (('location' in resp.headers and resp.status_code in REDIRECT_STAT I)):
77 prepared_request = req.copy()
83 78
84 resp.content # Consume socket so it can be released 79 resp.content # Consume socket so it can be released
85 80
86 if i >= self.max_redirects: 81 if i >= self.max_redirects:
87 raise TooManyRedirects('Exceeded %s redirects.' % self.max_redir ects) 82 raise TooManyRedirects('Exceeded %s redirects.' % self.max_redir ects)
88 83
89 # Release the connection back into the pool. 84 # Release the connection back into the pool.
90 resp.close() 85 resp.close()
91 86
92 url = resp.headers['location'] 87 url = resp.headers['location']
93 method = prepared_request.method 88 method = req.method
94 89
95 # Handle redirection without scheme (see: RFC 1808 Section 4) 90 # Handle redirection without scheme (see: RFC 1808 Section 4)
96 if url.startswith('//'): 91 if url.startswith('//'):
97 parsed_rurl = urlparse(resp.url) 92 parsed_rurl = urlparse(resp.url)
98 url = '%s:%s' % (parsed_rurl.scheme, url) 93 url = '%s:%s' % (parsed_rurl.scheme, url)
99 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 100 # Facilitate non-RFC2616-compliant 'location' headers
101 # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/re source') 101 # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/re source')
102 # Compliant with RFC3986, we percent encode the url. 102 # Compliant with RFC3986, we percent encode the url.
103 if not urlparse(url).netloc: 103 if not urlparse(url).netloc:
104 url = urljoin(resp.url, requote_uri(url)) 104 url = urljoin(resp.url, requote_uri(url))
105 else: 105 else:
106 url = requote_uri(url) 106 url = requote_uri(url)
107 107
108 prepared_request.url = url 108 prepared_request.url = url
109 109
110 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4 110 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
111 if (resp.status_code == codes.see_other and 111 if (resp.status_code == codes.see_other and
112 prepared_request.method != 'HEAD'): 112 method != 'HEAD'):
113 method = 'GET' 113 method = 'GET'
114 114
115 # Do what the browsers do, despite standards... 115 # Do what the browsers do, despite standards...
116 if (resp.status_code in (codes.moved, codes.found) and 116 if (resp.status_code in (codes.moved, codes.found) and
117 prepared_request.method not in ('GET', 'HEAD')): 117 method not in ('GET', 'HEAD')):
118 method = 'GET' 118 method = 'GET'
119 119
120 prepared_request.method = method 120 prepared_request.method = method
121 121
122 # https://github.com/kennethreitz/requests/issues/1084 122 # https://github.com/kennethreitz/requests/issues/1084
123 if resp.status_code not in (codes.temporary, codes.resume): 123 if resp.status_code not in (codes.temporary, codes.resume):
124 if 'Content-Length' in prepared_request.headers: 124 if 'Content-Length' in prepared_request.headers:
125 del prepared_request.headers['Content-Length'] 125 del prepared_request.headers['Content-Length']
126 126
127 prepared_request.body = None 127 prepared_request.body = None
(...skipping 18 matching lines...) Expand all
146 146
147 extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) 147 extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)
148 148
149 i += 1 149 i += 1
150 yield resp 150 yield resp
151 151
152 152
153 class Session(SessionRedirectMixin): 153 class Session(SessionRedirectMixin):
154 """A Requests session. 154 """A Requests session.
155 155
156 Provides cookie persistience, connection-pooling, and configuration. 156 Provides cookie persistence, connection-pooling, and configuration.
157 157
158 Basic Usage:: 158 Basic Usage::
159 159
160 >>> import requests 160 >>> import requests
161 >>> s = requests.Session() 161 >>> s = requests.Session()
162 >>> s.get('http://httpbin.org/get') 162 >>> s.get('http://httpbin.org/get')
163 200 163 200
164 """ 164 """
165 165
166 __attrs__ = [ 166 __attrs__ = [
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 #: SSL certificate default. 201 #: SSL certificate default.
202 self.cert = None 202 self.cert = None
203 203
204 #: Maximum number of redirects allowed. If the request exceeds this 204 #: Maximum number of redirects allowed. If the request exceeds this
205 #: limit, a :class:`TooManyRedirects` exception is raised. 205 #: limit, a :class:`TooManyRedirects` exception is raised.
206 self.max_redirects = DEFAULT_REDIRECT_LIMIT 206 self.max_redirects = DEFAULT_REDIRECT_LIMIT
207 207
208 #: Should we trust the environment? 208 #: Should we trust the environment?
209 self.trust_env = True 209 self.trust_env = True
210 210
211 # Set up a CookieJar to be used by default 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.
212 self.cookies = cookiejar_from_dict({}) 215 self.cookies = cookiejar_from_dict({})
213 216
214 # Default connection adapters. 217 # Default connection adapters.
215 self.adapters = OrderedDict() 218 self.adapters = OrderedDict()
216 self.mount('https://', HTTPAdapter()) 219 self.mount('https://', HTTPAdapter())
217 self.mount('http://', HTTPAdapter()) 220 self.mount('http://', HTTPAdapter())
218 221
219 def __enter__(self): 222 def __enter__(self):
220 return self 223 return self
221 224
222 def __exit__(self, *args): 225 def __exit__(self, *args):
223 self.close() 226 self.close()
224 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
225 def request(self, method, url, 268 def request(self, method, url,
226 params=None, 269 params=None,
227 data=None, 270 data=None,
228 headers=None, 271 headers=None,
229 cookies=None, 272 cookies=None,
230 files=None, 273 files=None,
231 auth=None, 274 auth=None,
232 timeout=None, 275 timeout=None,
233 allow_redirects=True, 276 allow_redirects=True,
234 proxies=None, 277 proxies=None,
(...skipping 23 matching lines...) Expand all
258 :param allow_redirects: (optional) Boolean. Set to True by default. 301 :param allow_redirects: (optional) Boolean. Set to True by default.
259 :param proxies: (optional) Dictionary mapping protocol to the URL of 302 :param proxies: (optional) Dictionary mapping protocol to the URL of
260 the proxy. 303 the proxy.
261 :param stream: (optional) whether to immediately download the response 304 :param stream: (optional) whether to immediately download the response
262 content. Defaults to ``False``. 305 content. Defaults to ``False``.
263 :param verify: (optional) if ``True``, the SSL cert will be verified. 306 :param verify: (optional) if ``True``, the SSL cert will be verified.
264 A CA_BUNDLE path can also be provided. 307 A CA_BUNDLE path can also be provided.
265 :param cert: (optional) if String, path to ssl client cert file (.pem). 308 :param cert: (optional) if String, path to ssl client cert file (.pem).
266 If Tuple, ('cert', 'key') pair. 309 If Tuple, ('cert', 'key') pair.
267 """ 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)
268 324
269 cookies = cookies or {}
270 proxies = proxies or {} 325 proxies = proxies or {}
271 326
272 # Bootstrap CookieJar.
273 if not isinstance(cookies, cookielib.CookieJar):
274 cookies = cookiejar_from_dict(cookies)
275
276 # Merge with session cookies
277 merged_cookies = RequestsCookieJar()
278 merged_cookies.update(self.cookies)
279 merged_cookies.update(cookies)
280 cookies = merged_cookies
281
282 # Gather clues from the surrounding environment. 327 # Gather clues from the surrounding environment.
283 if self.trust_env: 328 if self.trust_env:
284 # Set environment's proxies. 329 # Set environment's proxies.
285 env_proxies = get_environ_proxies(url) or {} 330 env_proxies = get_environ_proxies(url) or {}
286 for (k, v) in env_proxies.items(): 331 for (k, v) in env_proxies.items():
287 proxies.setdefault(k, v) 332 proxies.setdefault(k, v)
288 333
289 # Set environment's basic authentication.
290 if not auth:
291 auth = get_netrc_auth(url)
292
293 # Look for configuration. 334 # Look for configuration.
294 if not verify and verify is not False: 335 if not verify and verify is not False:
295 verify = os.environ.get('REQUESTS_CA_BUNDLE') 336 verify = os.environ.get('REQUESTS_CA_BUNDLE')
296 337
297 # Curl compatibility. 338 # Curl compatibility.
298 if not verify and verify is not False: 339 if not verify and verify is not False:
299 verify = os.environ.get('CURL_CA_BUNDLE') 340 verify = os.environ.get('CURL_CA_BUNDLE')
300 341
301 # Merge all the kwargs. 342 # Merge all the kwargs.
302 params = merge_setting(params, self.params)
303 headers = merge_setting(headers, self.headers, dict_class=CaseInsensitiv eDict)
304 auth = merge_setting(auth, self.auth)
305 proxies = merge_setting(proxies, self.proxies) 343 proxies = merge_setting(proxies, self.proxies)
306 hooks = merge_setting(hooks, self.hooks)
307 stream = merge_setting(stream, self.stream) 344 stream = merge_setting(stream, self.stream)
308 verify = merge_setting(verify, self.verify) 345 verify = merge_setting(verify, self.verify)
309 cert = merge_setting(cert, self.cert) 346 cert = merge_setting(cert, self.cert)
310 347
311 # Create the Request.
312 req = Request()
313 req.method = method.upper()
314 req.url = url
315 req.headers = headers
316 req.files = files
317 req.data = data
318 req.params = params
319 req.auth = auth
320 req.cookies = cookies
321 req.hooks = hooks
322
323 # Prepare the Request.
324 prep = req.prepare()
325
326 # Send the request. 348 # Send the request.
327 send_kwargs = { 349 send_kwargs = {
328 'stream': stream, 350 'stream': stream,
329 'timeout': timeout, 351 'timeout': timeout,
330 'verify': verify, 352 'verify': verify,
331 'cert': cert, 353 'cert': cert,
332 'proxies': proxies, 354 'proxies': proxies,
333 'allow_redirects': allow_redirects, 355 'allow_redirects': allow_redirects,
334 } 356 }
335 resp = self.send(prep, **send_kwargs) 357 resp = self.send(prep, **send_kwargs)
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
409 """Send a given PreparedRequest.""" 431 """Send a given PreparedRequest."""
410 # Set defaults that the hooks can utilize to ensure they always have 432 # Set defaults that the hooks can utilize to ensure they always have
411 # the correct parameters to reproduce the previous request. 433 # the correct parameters to reproduce the previous request.
412 kwargs.setdefault('stream', self.stream) 434 kwargs.setdefault('stream', self.stream)
413 kwargs.setdefault('verify', self.verify) 435 kwargs.setdefault('verify', self.verify)
414 kwargs.setdefault('cert', self.cert) 436 kwargs.setdefault('cert', self.cert)
415 kwargs.setdefault('proxies', self.proxies) 437 kwargs.setdefault('proxies', self.proxies)
416 438
417 # It's possible that users might accidentally send a Request object. 439 # It's possible that users might accidentally send a Request object.
418 # Guard against that specific failure case. 440 # Guard against that specific failure case.
419 if getattr(request, 'prepare', None): 441 if not isinstance(request, PreparedRequest):
420 raise ValueError('You can only send PreparedRequests.') 442 raise ValueError('You can only send PreparedRequests.')
421 443
422 # Set up variables needed for resolve_redirects and dispatching of 444 # Set up variables needed for resolve_redirects and dispatching of
423 # hooks 445 # hooks
424 allow_redirects = kwargs.pop('allow_redirects', True) 446 allow_redirects = kwargs.pop('allow_redirects', True)
425 stream = kwargs.get('stream') 447 stream = kwargs.get('stream')
426 timeout = kwargs.get('timeout') 448 timeout = kwargs.get('timeout')
427 verify = kwargs.get('verify') 449 verify = kwargs.get('verify')
428 cert = kwargs.get('cert') 450 cert = kwargs.get('cert')
429 proxies = kwargs.get('proxies') 451 proxies = kwargs.get('proxies')
430 hooks = request.hooks 452 hooks = request.hooks
431 453
432 # Get the appropriate adapter to use 454 # Get the appropriate adapter to use
433 adapter = self.get_adapter(url=request.url) 455 adapter = self.get_adapter(url=request.url)
434 456
435 # Start time (approximately) of the request 457 # Start time (approximately) of the request
436 start = datetime.utcnow() 458 start = datetime.utcnow()
437 # Send the request 459 # Send the request
438 r = adapter.send(request, **kwargs) 460 r = adapter.send(request, **kwargs)
439 # Total elapsed time of the request (approximately) 461 # Total elapsed time of the request (approximately)
440 r.elapsed = datetime.utcnow() - start 462 r.elapsed = datetime.utcnow() - start
441 463
442 # Response manipulation hooks 464 # Response manipulation hooks
443 r = dispatch_hook('response', hooks, r, **kwargs) 465 r = dispatch_hook('response', hooks, r, **kwargs)
444 466
445 # Persist cookies 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)
446 extract_cookies_to_jar(self.cookies, request, r.raw) 472 extract_cookies_to_jar(self.cookies, request, r.raw)
447 473
448 # Redirect resolving generator. 474 # Redirect resolving generator.
449 gen = self.resolve_redirects(r, request, stream=stream, 475 gen = self.resolve_redirects(r, request, stream=stream,
450 timeout=timeout, verify=verify, cert=cert, 476 timeout=timeout, verify=verify, cert=cert,
451 proxies=proxies) 477 proxies=proxies)
452 478
453 # Resolve redirects if allowed. 479 # Resolve redirects if allowed.
454 history = [resp for resp in gen] if allow_redirects else [] 480 history = [resp for resp in gen] if allow_redirects else []
455 481
456 # Shuffle things around if there's history. 482 # Shuffle things around if there's history.
457 if history: 483 if history:
458 # Insert the first (original) request at the start 484 # Insert the first (original) request at the start
459 history.insert(0, r) 485 history.insert(0, r)
460 # Get the last request made 486 # Get the last request made
461 r = history.pop() 487 r = history.pop()
462 r.history = tuple(history) 488 r.history = tuple(history)
463 489
464 return r 490 return r
465 491
466 def get_adapter(self, url): 492 def get_adapter(self, url):
467 """Returns the appropriate connnection adapter for the given URL.""" 493 """Returns the appropriate connnection adapter for the given URL."""
468 for (prefix, adapter) in self.adapters.items(): 494 for (prefix, adapter) in self.adapters.items():
469 495
470 if url.startswith(prefix): 496 if url.lower().startswith(prefix):
471 return adapter 497 return adapter
472 498
473 # Nothing matches :-/ 499 # Nothing matches :-/
474 raise InvalidSchema("No connection adapters were found for '%s'" % url) 500 raise InvalidSchema("No connection adapters were found for '%s'" % url)
475 501
476 def close(self): 502 def close(self):
477 """Closes all adapters and as such the session""" 503 """Closes all adapters and as such the session"""
478 for _, v in self.adapters.items(): 504 for v in self.adapters.values():
479 v.close() 505 v.close()
480 506
481 def mount(self, prefix, adapter): 507 def mount(self, prefix, adapter):
482 """Registers a connection adapter to a prefix. 508 """Registers a connection adapter to a prefix.
483 509
484 Adapters are sorted in descending order by key length.""" 510 Adapters are sorted in descending order by key length."""
485 self.adapters[prefix] = adapter 511 self.adapters[prefix] = adapter
486 keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] 512 keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
487 for key in keys_to_move: 513 for key in keys_to_move:
488 self.adapters[key] = self.adapters.pop(key) 514 self.adapters[key] = self.adapters.pop(key)
489 515
490 def __getstate__(self): 516 def __getstate__(self):
491 return dict((attr, getattr(self, attr, None)) for attr in self.__attrs__ ) 517 return dict((attr, getattr(self, attr, None)) for attr in self.__attrs__ )
492 518
493 def __setstate__(self, state): 519 def __setstate__(self, state):
494 for attr, value in state.items(): 520 for attr, value in state.items():
495 setattr(self, attr, value) 521 setattr(self, attr, value)
496 522
497 523
498 def session(): 524 def session():
499 """Returns a :class:`Session` for context-management.""" 525 """Returns a :class:`Session` for context-management."""
500 526
501 return Session() 527 return Session()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698