| Index: third_party/google-endpoints/requests/sessions.py
|
| diff --git a/third_party/google-endpoints/requests/sessions.py b/third_party/google-endpoints/requests/sessions.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7983282a6de0700b7e42e687196497b18c8c6b71
|
| --- /dev/null
|
| +++ b/third_party/google-endpoints/requests/sessions.py
|
| @@ -0,0 +1,725 @@
|
| +# -*- coding: utf-8 -*-
|
| +
|
| +"""
|
| +requests.session
|
| +~~~~~~~~~~~~~~~~
|
| +
|
| +This module provides a Session object to manage and persist settings across
|
| +requests (cookies, auth, proxies).
|
| +"""
|
| +import os
|
| +from collections import Mapping
|
| +from datetime import datetime
|
| +
|
| +from .auth import _basic_auth_str
|
| +from .compat import cookielib, OrderedDict, urljoin, urlparse
|
| +from .cookies import (
|
| + cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
|
| +from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
|
| +from .hooks import default_hooks, dispatch_hook
|
| +from ._internal_utils import to_native_string
|
| +from .utils import to_key_val_list, default_headers
|
| +from .exceptions import (
|
| + TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError)
|
| +from .packages.urllib3._collections import RecentlyUsedContainer
|
| +from .structures import CaseInsensitiveDict
|
| +
|
| +from .adapters import HTTPAdapter
|
| +
|
| +from .utils import (
|
| + requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies,
|
| + get_auth_from_url, rewind_body
|
| +)
|
| +
|
| +from .status_codes import codes
|
| +
|
| +# formerly defined here, reexposed here for backward compatibility
|
| +from .models import REDIRECT_STATI
|
| +
|
| +REDIRECT_CACHE_SIZE = 1000
|
| +
|
| +
|
| +def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
|
| + """Determines appropriate setting for a given request, taking into account
|
| + the explicit setting on that request, and the setting in the session. If a
|
| + setting is a dictionary, they will be merged together using `dict_class`
|
| + """
|
| +
|
| + if session_setting is None:
|
| + return request_setting
|
| +
|
| + if request_setting is None:
|
| + return session_setting
|
| +
|
| + # Bypass if not a dictionary (e.g. verify)
|
| + if not (
|
| + isinstance(session_setting, Mapping) and
|
| + isinstance(request_setting, Mapping)
|
| + ):
|
| + return request_setting
|
| +
|
| + merged_setting = dict_class(to_key_val_list(session_setting))
|
| + merged_setting.update(to_key_val_list(request_setting))
|
| +
|
| + # Remove keys that are set to None. Extract keys first to avoid altering
|
| + # the dictionary during iteration.
|
| + none_keys = [k for (k, v) in merged_setting.items() if v is None]
|
| + for key in none_keys:
|
| + del merged_setting[key]
|
| +
|
| + return merged_setting
|
| +
|
| +
|
| +def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):
|
| + """Properly merges both requests and session hooks.
|
| +
|
| + This is necessary because when request_hooks == {'response': []}, the
|
| + merge breaks Session hooks entirely.
|
| + """
|
| + if session_hooks is None or session_hooks.get('response') == []:
|
| + return request_hooks
|
| +
|
| + if request_hooks is None or request_hooks.get('response') == []:
|
| + return session_hooks
|
| +
|
| + return merge_setting(request_hooks, session_hooks, dict_class)
|
| +
|
| +
|
| +class SessionRedirectMixin(object):
|
| + def resolve_redirects(self, resp, req, stream=False, timeout=None,
|
| + verify=True, cert=None, proxies=None, **adapter_kwargs):
|
| + """Receives a Response. Returns a generator of Responses."""
|
| +
|
| + i = 0
|
| + hist = [] # keep track of history
|
| +
|
| + while resp.is_redirect:
|
| + prepared_request = req.copy()
|
| +
|
| + if i > 0:
|
| + # Update history and keep track of redirects.
|
| + hist.append(resp)
|
| + new_hist = list(hist)
|
| + resp.history = new_hist
|
| +
|
| + try:
|
| + resp.content # Consume socket so it can be released
|
| + except (ChunkedEncodingError, ContentDecodingError, RuntimeError):
|
| + resp.raw.read(decode_content=False)
|
| +
|
| + if i >= self.max_redirects:
|
| + raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects, response=resp)
|
| +
|
| + # Release the connection back into the pool.
|
| + resp.close()
|
| +
|
| + url = resp.headers['location']
|
| +
|
| + # Handle redirection without scheme (see: RFC 1808 Section 4)
|
| + if url.startswith('//'):
|
| + parsed_rurl = urlparse(resp.url)
|
| + url = '%s:%s' % (parsed_rurl.scheme, url)
|
| +
|
| + # The scheme should be lower case...
|
| + parsed = urlparse(url)
|
| + url = parsed.geturl()
|
| +
|
| + # Facilitate relative 'location' headers, as allowed by RFC 7231.
|
| + # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
|
| + # Compliant with RFC3986, we percent encode the url.
|
| + if not parsed.netloc:
|
| + url = urljoin(resp.url, requote_uri(url))
|
| + else:
|
| + url = requote_uri(url)
|
| +
|
| + prepared_request.url = to_native_string(url)
|
| + # Cache the url, unless it redirects to itself.
|
| + if resp.is_permanent_redirect and req.url != prepared_request.url:
|
| + self.redirect_cache[req.url] = prepared_request.url
|
| +
|
| + self.rebuild_method(prepared_request, resp)
|
| +
|
| + # https://github.com/kennethreitz/requests/issues/1084
|
| + if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect):
|
| + # https://github.com/kennethreitz/requests/issues/3490
|
| + purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding')
|
| + for header in purged_headers:
|
| + prepared_request.headers.pop(header, None)
|
| + prepared_request.body = None
|
| +
|
| + headers = prepared_request.headers
|
| + try:
|
| + del headers['Cookie']
|
| + except KeyError:
|
| + pass
|
| +
|
| + # Extract any cookies sent on the response to the cookiejar
|
| + # in the new request. Because we've mutated our copied prepared
|
| + # request, use the old one that we haven't yet touched.
|
| + extract_cookies_to_jar(prepared_request._cookies, req, resp.raw)
|
| + merge_cookies(prepared_request._cookies, self.cookies)
|
| + prepared_request.prepare_cookies(prepared_request._cookies)
|
| +
|
| + # Rebuild auth and proxy information.
|
| + proxies = self.rebuild_proxies(prepared_request, proxies)
|
| + self.rebuild_auth(prepared_request, resp)
|
| +
|
| + # A failed tell() sets `_body_position` to `object()`. This non-None
|
| + # value ensures `rewindable` will be True, allowing us to raise an
|
| + # UnrewindableBodyError, instead of hanging the connection.
|
| + rewindable = (
|
| + prepared_request._body_position is not None and
|
| + ('Content-Length' in headers or 'Transfer-Encoding' in headers)
|
| + )
|
| +
|
| + # Attempt to rewind consumed file-like object.
|
| + if rewindable:
|
| + rewind_body(prepared_request)
|
| +
|
| + # Override the original request.
|
| + req = prepared_request
|
| +
|
| + resp = self.send(
|
| + req,
|
| + stream=stream,
|
| + timeout=timeout,
|
| + verify=verify,
|
| + cert=cert,
|
| + proxies=proxies,
|
| + allow_redirects=False,
|
| + **adapter_kwargs
|
| + )
|
| +
|
| + extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)
|
| +
|
| + i += 1
|
| + yield resp
|
| +
|
| + def rebuild_auth(self, prepared_request, response):
|
| + """When being redirected we may want to strip authentication from the
|
| + request to avoid leaking credentials. This method intelligently removes
|
| + and reapplies authentication where possible to avoid credential loss.
|
| + """
|
| + headers = prepared_request.headers
|
| + url = prepared_request.url
|
| +
|
| + if 'Authorization' in headers:
|
| + # If we get redirected to a new host, we should strip out any
|
| + # authentication headers.
|
| + original_parsed = urlparse(response.request.url)
|
| + redirect_parsed = urlparse(url)
|
| +
|
| + if (original_parsed.hostname != redirect_parsed.hostname):
|
| + del headers['Authorization']
|
| +
|
| + # .netrc might have more auth for us on our new host.
|
| + new_auth = get_netrc_auth(url) if self.trust_env else None
|
| + if new_auth is not None:
|
| + prepared_request.prepare_auth(new_auth)
|
| +
|
| + return
|
| +
|
| + def rebuild_proxies(self, prepared_request, proxies):
|
| + """This method re-evaluates the proxy configuration by considering the
|
| + environment variables. If we are redirected to a URL covered by
|
| + NO_PROXY, we strip the proxy configuration. Otherwise, we set missing
|
| + proxy keys for this URL (in case they were stripped by a previous
|
| + redirect).
|
| +
|
| + This method also replaces the Proxy-Authorization header where
|
| + necessary.
|
| +
|
| + :rtype: dict
|
| + """
|
| + headers = prepared_request.headers
|
| + url = prepared_request.url
|
| + scheme = urlparse(url).scheme
|
| + new_proxies = proxies.copy() if proxies is not None else {}
|
| +
|
| + if self.trust_env and not should_bypass_proxies(url):
|
| + environ_proxies = get_environ_proxies(url)
|
| +
|
| + proxy = environ_proxies.get(scheme, environ_proxies.get('all'))
|
| +
|
| + if proxy:
|
| + new_proxies.setdefault(scheme, proxy)
|
| +
|
| + if 'Proxy-Authorization' in headers:
|
| + del headers['Proxy-Authorization']
|
| +
|
| + try:
|
| + username, password = get_auth_from_url(new_proxies[scheme])
|
| + except KeyError:
|
| + username, password = None, None
|
| +
|
| + if username and password:
|
| + headers['Proxy-Authorization'] = _basic_auth_str(username, password)
|
| +
|
| + return new_proxies
|
| +
|
| + def rebuild_method(self, prepared_request, response):
|
| + """When being redirected we may want to change the method of the request
|
| + based on certain specs or browser behavior.
|
| + """
|
| + method = prepared_request.method
|
| +
|
| + # http://tools.ietf.org/html/rfc7231#section-6.4.4
|
| + if response.status_code == codes.see_other and method != 'HEAD':
|
| + method = 'GET'
|
| +
|
| + # Do what the browsers do, despite standards...
|
| + # First, turn 302s into GETs.
|
| + if response.status_code == codes.found and method != 'HEAD':
|
| + method = 'GET'
|
| +
|
| + # Second, if a POST is responded to with a 301, turn it into a GET.
|
| + # This bizarre behaviour is explained in Issue 1704.
|
| + if response.status_code == codes.moved and method == 'POST':
|
| + method = 'GET'
|
| +
|
| + prepared_request.method = method
|
| +
|
| +
|
| +class Session(SessionRedirectMixin):
|
| + """A Requests session.
|
| +
|
| + Provides cookie persistence, connection-pooling, and configuration.
|
| +
|
| + Basic Usage::
|
| +
|
| + >>> import requests
|
| + >>> s = requests.Session()
|
| + >>> s.get('http://httpbin.org/get')
|
| + <Response [200]>
|
| +
|
| + Or as a context manager::
|
| +
|
| + >>> with requests.Session() as s:
|
| + >>> s.get('http://httpbin.org/get')
|
| + <Response [200]>
|
| + """
|
| +
|
| + __attrs__ = [
|
| + 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify',
|
| + 'cert', 'prefetch', 'adapters', 'stream', 'trust_env',
|
| + 'max_redirects',
|
| + ]
|
| +
|
| + def __init__(self):
|
| +
|
| + #: A case-insensitive dictionary of headers to be sent on each
|
| + #: :class:`Request <Request>` sent from this
|
| + #: :class:`Session <Session>`.
|
| + self.headers = default_headers()
|
| +
|
| + #: Default Authentication tuple or object to attach to
|
| + #: :class:`Request <Request>`.
|
| + self.auth = None
|
| +
|
| + #: Dictionary mapping protocol or protocol and host to the URL of the proxy
|
| + #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to
|
| + #: be used on each :class:`Request <Request>`.
|
| + self.proxies = {}
|
| +
|
| + #: Event-handling hooks.
|
| + self.hooks = default_hooks()
|
| +
|
| + #: Dictionary of querystring data to attach to each
|
| + #: :class:`Request <Request>`. The dictionary values may be lists for
|
| + #: representing multivalued query parameters.
|
| + self.params = {}
|
| +
|
| + #: Stream response content default.
|
| + self.stream = False
|
| +
|
| + #: SSL Verification default.
|
| + self.verify = True
|
| +
|
| + #: SSL client certificate default.
|
| + self.cert = None
|
| +
|
| + #: Maximum number of redirects allowed. If the request exceeds this
|
| + #: limit, a :class:`TooManyRedirects` exception is raised.
|
| + #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is
|
| + #: 30.
|
| + self.max_redirects = DEFAULT_REDIRECT_LIMIT
|
| +
|
| + #: Trust environment settings for proxy configuration, default
|
| + #: authentication and similar.
|
| + self.trust_env = True
|
| +
|
| + #: A CookieJar containing all currently outstanding cookies set on this
|
| + #: session. By default it is a
|
| + #: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but
|
| + #: may be any other ``cookielib.CookieJar`` compatible object.
|
| + self.cookies = cookiejar_from_dict({})
|
| +
|
| + # Default connection adapters.
|
| + self.adapters = OrderedDict()
|
| + self.mount('https://', HTTPAdapter())
|
| + self.mount('http://', HTTPAdapter())
|
| +
|
| + # Only store 1000 redirects to prevent using infinite memory
|
| + self.redirect_cache = RecentlyUsedContainer(REDIRECT_CACHE_SIZE)
|
| +
|
| + def __enter__(self):
|
| + return self
|
| +
|
| + def __exit__(self, *args):
|
| + self.close()
|
| +
|
| + def prepare_request(self, request):
|
| + """Constructs a :class:`PreparedRequest <PreparedRequest>` for
|
| + transmission and returns it. The :class:`PreparedRequest` has settings
|
| + merged from the :class:`Request <Request>` instance and those of the
|
| + :class:`Session`.
|
| +
|
| + :param request: :class:`Request` instance to prepare with this
|
| + session's settings.
|
| + :rtype: requests.PreparedRequest
|
| + """
|
| + cookies = request.cookies or {}
|
| +
|
| + # Bootstrap CookieJar.
|
| + if not isinstance(cookies, cookielib.CookieJar):
|
| + cookies = cookiejar_from_dict(cookies)
|
| +
|
| + # Merge with session cookies
|
| + merged_cookies = merge_cookies(
|
| + merge_cookies(RequestsCookieJar(), self.cookies), cookies)
|
| +
|
| + # Set environment's basic authentication if not explicitly set.
|
| + auth = request.auth
|
| + if self.trust_env and not auth and not self.auth:
|
| + auth = get_netrc_auth(request.url)
|
| +
|
| + p = PreparedRequest()
|
| + p.prepare(
|
| + method=request.method.upper(),
|
| + url=request.url,
|
| + files=request.files,
|
| + data=request.data,
|
| + json=request.json,
|
| + headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict),
|
| + params=merge_setting(request.params, self.params),
|
| + auth=merge_setting(auth, self.auth),
|
| + cookies=merged_cookies,
|
| + hooks=merge_hooks(request.hooks, self.hooks),
|
| + )
|
| + return p
|
| +
|
| + def request(self, method, url,
|
| + params=None,
|
| + data=None,
|
| + headers=None,
|
| + cookies=None,
|
| + files=None,
|
| + auth=None,
|
| + timeout=None,
|
| + allow_redirects=True,
|
| + proxies=None,
|
| + hooks=None,
|
| + stream=None,
|
| + verify=None,
|
| + cert=None,
|
| + json=None):
|
| + """Constructs a :class:`Request <Request>`, prepares it and sends it.
|
| + Returns :class:`Response <Response>` object.
|
| +
|
| + :param method: method for the new :class:`Request` object.
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param params: (optional) Dictionary or bytes to be sent in the query
|
| + string for the :class:`Request`.
|
| + :param data: (optional) Dictionary, bytes, or file-like object to send
|
| + in the body of the :class:`Request`.
|
| + :param json: (optional) json to send in the body of the
|
| + :class:`Request`.
|
| + :param headers: (optional) Dictionary of HTTP Headers to send with the
|
| + :class:`Request`.
|
| + :param cookies: (optional) Dict or CookieJar object to send with the
|
| + :class:`Request`.
|
| + :param files: (optional) Dictionary of ``'filename': file-like-objects``
|
| + for multipart encoding upload.
|
| + :param auth: (optional) Auth tuple or callable to enable
|
| + Basic/Digest/Custom HTTP Auth.
|
| + :param timeout: (optional) How long to wait for the server to send
|
| + data before giving up, as a float, or a :ref:`(connect timeout,
|
| + read timeout) <timeouts>` tuple.
|
| + :type timeout: float or tuple
|
| + :param allow_redirects: (optional) Set to True by default.
|
| + :type allow_redirects: bool
|
| + :param proxies: (optional) Dictionary mapping protocol or protocol and
|
| + hostname to the URL of the proxy.
|
| + :param stream: (optional) whether to immediately download the response
|
| + content. Defaults to ``False``.
|
| + :param verify: (optional) whether the SSL cert will be verified.
|
| + A CA_BUNDLE path can also be provided. Defaults to ``True``.
|
| + :param cert: (optional) if String, path to ssl client cert file (.pem).
|
| + If Tuple, ('cert', 'key') pair.
|
| + :rtype: requests.Response
|
| + """
|
| + # Create the Request.
|
| + req = Request(
|
| + method = method.upper(),
|
| + url = url,
|
| + headers = headers,
|
| + files = files,
|
| + data = data or {},
|
| + json = json,
|
| + params = params or {},
|
| + auth = auth,
|
| + cookies = cookies,
|
| + hooks = hooks,
|
| + )
|
| + prep = self.prepare_request(req)
|
| +
|
| + proxies = proxies or {}
|
| +
|
| + settings = self.merge_environment_settings(
|
| + prep.url, proxies, stream, verify, cert
|
| + )
|
| +
|
| + # Send the request.
|
| + send_kwargs = {
|
| + 'timeout': timeout,
|
| + 'allow_redirects': allow_redirects,
|
| + }
|
| + send_kwargs.update(settings)
|
| + resp = self.send(prep, **send_kwargs)
|
| +
|
| + return resp
|
| +
|
| + def get(self, url, **kwargs):
|
| + """Sends a GET request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + kwargs.setdefault('allow_redirects', True)
|
| + return self.request('GET', url, **kwargs)
|
| +
|
| + def options(self, url, **kwargs):
|
| + """Sends a OPTIONS request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + kwargs.setdefault('allow_redirects', True)
|
| + return self.request('OPTIONS', url, **kwargs)
|
| +
|
| + def head(self, url, **kwargs):
|
| + """Sends a HEAD request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + kwargs.setdefault('allow_redirects', False)
|
| + return self.request('HEAD', url, **kwargs)
|
| +
|
| + def post(self, url, data=None, json=None, **kwargs):
|
| + """Sends a POST request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
| + :param json: (optional) json to send in the body of the :class:`Request`.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + return self.request('POST', url, data=data, json=json, **kwargs)
|
| +
|
| + def put(self, url, data=None, **kwargs):
|
| + """Sends a PUT request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + return self.request('PUT', url, data=data, **kwargs)
|
| +
|
| + def patch(self, url, data=None, **kwargs):
|
| + """Sends a PATCH request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + return self.request('PATCH', url, data=data, **kwargs)
|
| +
|
| + def delete(self, url, **kwargs):
|
| + """Sends a DELETE request. Returns :class:`Response` object.
|
| +
|
| + :param url: URL for the new :class:`Request` object.
|
| + :param \*\*kwargs: Optional arguments that ``request`` takes.
|
| + :rtype: requests.Response
|
| + """
|
| +
|
| + return self.request('DELETE', url, **kwargs)
|
| +
|
| + def send(self, request, **kwargs):
|
| + """
|
| + Send a given PreparedRequest.
|
| +
|
| + :rtype: requests.Response
|
| + """
|
| + # Set defaults that the hooks can utilize to ensure they always have
|
| + # the correct parameters to reproduce the previous request.
|
| + kwargs.setdefault('stream', self.stream)
|
| + kwargs.setdefault('verify', self.verify)
|
| + kwargs.setdefault('cert', self.cert)
|
| + kwargs.setdefault('proxies', self.proxies)
|
| +
|
| + # It's possible that users might accidentally send a Request object.
|
| + # Guard against that specific failure case.
|
| + if isinstance(request, Request):
|
| + raise ValueError('You can only send PreparedRequests.')
|
| +
|
| + # Set up variables needed for resolve_redirects and dispatching of hooks
|
| + allow_redirects = kwargs.pop('allow_redirects', True)
|
| + stream = kwargs.get('stream')
|
| + hooks = request.hooks
|
| +
|
| + # Resolve URL in redirect cache, if available.
|
| + if allow_redirects:
|
| + checked_urls = set()
|
| + while request.url in self.redirect_cache:
|
| + checked_urls.add(request.url)
|
| + new_url = self.redirect_cache.get(request.url)
|
| + if new_url in checked_urls:
|
| + break
|
| + request.url = new_url
|
| +
|
| + # Get the appropriate adapter to use
|
| + adapter = self.get_adapter(url=request.url)
|
| +
|
| + # Start time (approximately) of the request
|
| + start = datetime.utcnow()
|
| +
|
| + # Send the request
|
| + r = adapter.send(request, **kwargs)
|
| +
|
| + # Total elapsed time of the request (approximately)
|
| + r.elapsed = datetime.utcnow() - start
|
| +
|
| + # Response manipulation hooks
|
| + r = dispatch_hook('response', hooks, r, **kwargs)
|
| +
|
| + # Persist cookies
|
| + if r.history:
|
| +
|
| + # If the hooks create history then we want those cookies too
|
| + for resp in r.history:
|
| + extract_cookies_to_jar(self.cookies, resp.request, resp.raw)
|
| +
|
| + extract_cookies_to_jar(self.cookies, request, r.raw)
|
| +
|
| + # Redirect resolving generator.
|
| + gen = self.resolve_redirects(r, request, **kwargs)
|
| +
|
| + # Resolve redirects if allowed.
|
| + history = [resp for resp in gen] if allow_redirects else []
|
| +
|
| + # Shuffle things around if there's history.
|
| + if history:
|
| + # Insert the first (original) request at the start
|
| + history.insert(0, r)
|
| + # Get the last request made
|
| + r = history.pop()
|
| + r.history = history
|
| +
|
| + if not stream:
|
| + r.content
|
| +
|
| + return r
|
| +
|
| + def merge_environment_settings(self, url, proxies, stream, verify, cert):
|
| + """
|
| + Check the environment and merge it with some settings.
|
| +
|
| + :rtype: dict
|
| + """
|
| + # Gather clues from the surrounding environment.
|
| + if self.trust_env:
|
| + # Set environment's proxies.
|
| + env_proxies = get_environ_proxies(url) or {}
|
| + for (k, v) in env_proxies.items():
|
| + proxies.setdefault(k, v)
|
| +
|
| + # Look for requests environment configuration and be compatible
|
| + # with cURL.
|
| + if verify is True or verify is None:
|
| + verify = (os.environ.get('REQUESTS_CA_BUNDLE') or
|
| + os.environ.get('CURL_CA_BUNDLE'))
|
| +
|
| + # Merge all the kwargs.
|
| + proxies = merge_setting(proxies, self.proxies)
|
| + stream = merge_setting(stream, self.stream)
|
| + verify = merge_setting(verify, self.verify)
|
| + cert = merge_setting(cert, self.cert)
|
| +
|
| + return {'verify': verify, 'proxies': proxies, 'stream': stream,
|
| + 'cert': cert}
|
| +
|
| + def get_adapter(self, url):
|
| + """
|
| + Returns the appropriate connection adapter for the given URL.
|
| +
|
| + :rtype: requests.adapters.BaseAdapter
|
| + """
|
| + for (prefix, adapter) in self.adapters.items():
|
| +
|
| + if url.lower().startswith(prefix):
|
| + return adapter
|
| +
|
| + # Nothing matches :-/
|
| + raise InvalidSchema("No connection adapters were found for '%s'" % url)
|
| +
|
| + def close(self):
|
| + """Closes all adapters and as such the session"""
|
| + for v in self.adapters.values():
|
| + v.close()
|
| +
|
| + def mount(self, prefix, adapter):
|
| + """Registers a connection adapter to a prefix.
|
| +
|
| + Adapters are sorted in descending order by key length.
|
| + """
|
| + self.adapters[prefix] = adapter
|
| + keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
|
| +
|
| + for key in keys_to_move:
|
| + self.adapters[key] = self.adapters.pop(key)
|
| +
|
| + def __getstate__(self):
|
| + state = dict((attr, getattr(self, attr, None)) for attr in self.__attrs__)
|
| + state['redirect_cache'] = dict(self.redirect_cache)
|
| + return state
|
| +
|
| + def __setstate__(self, state):
|
| + redirect_cache = state.pop('redirect_cache', {})
|
| + for attr, value in state.items():
|
| + setattr(self, attr, value)
|
| +
|
| + self.redirect_cache = RecentlyUsedContainer(REDIRECT_CACHE_SIZE)
|
| + for redirect, to in redirect_cache.items():
|
| + self.redirect_cache[redirect] = to
|
| +
|
| +
|
| +def session():
|
| + """
|
| + Returns a :class:`Session` for context-management.
|
| +
|
| + :rtype: Session
|
| + """
|
| +
|
| + return Session()
|
|
|