| Index: third_party/requests/sessions.py
|
| diff --git a/third_party/requests/sessions.py b/third_party/requests/sessions.py
|
| index f4aeeee6df006f45a1e695813cf5b87e4f424d0c..aa956d3f3ff0506430e4bf100028bb7cee3e7745 100644
|
| --- a/third_party/requests/sessions.py
|
| +++ b/third_party/requests/sessions.py
|
| @@ -71,15 +71,10 @@ class SessionRedirectMixin(object):
|
| """Receives a Response. Returns a generator of Responses."""
|
|
|
| i = 0
|
| - prepared_request = PreparedRequest()
|
| - prepared_request.body = req.body
|
| - prepared_request.headers = req.headers.copy()
|
| - prepared_request.hooks = req.hooks
|
| - prepared_request.method = req.method
|
| - prepared_request.url = req.url
|
|
|
| # ((resp.status_code is codes.see_other))
|
| while (('location' in resp.headers and resp.status_code in REDIRECT_STATI)):
|
| + prepared_request = req.copy()
|
|
|
| resp.content # Consume socket so it can be released
|
|
|
| @@ -90,13 +85,18 @@ class SessionRedirectMixin(object):
|
| resp.close()
|
|
|
| url = resp.headers['location']
|
| - method = prepared_request.method
|
| + method = req.method
|
|
|
| # 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...
|
| + if '://' in url:
|
| + scheme, uri = url.split('://', 1)
|
| + url = '%s://%s' % (scheme.lower(), uri)
|
| +
|
| # Facilitate non-RFC2616-compliant 'location' headers
|
| # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
|
| # Compliant with RFC3986, we percent encode the url.
|
| @@ -109,12 +109,12 @@ class SessionRedirectMixin(object):
|
|
|
| # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
|
| if (resp.status_code == codes.see_other and
|
| - prepared_request.method != 'HEAD'):
|
| + method != 'HEAD'):
|
| method = 'GET'
|
|
|
| # Do what the browsers do, despite standards...
|
| if (resp.status_code in (codes.moved, codes.found) and
|
| - prepared_request.method not in ('GET', 'HEAD')):
|
| + method not in ('GET', 'HEAD')):
|
| method = 'GET'
|
|
|
| prepared_request.method = method
|
| @@ -153,7 +153,7 @@ class SessionRedirectMixin(object):
|
| class Session(SessionRedirectMixin):
|
| """A Requests session.
|
|
|
| - Provides cookie persistience, connection-pooling, and configuration.
|
| + Provides cookie persistence, connection-pooling, and configuration.
|
|
|
| Basic Usage::
|
|
|
| @@ -208,7 +208,10 @@ class Session(SessionRedirectMixin):
|
| #: Should we trust the environment?
|
| self.trust_env = True
|
|
|
| - # Set up a CookieJar to be used by default
|
| + #: 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.
|
| @@ -222,6 +225,46 @@ class Session(SessionRedirectMixin):
|
| 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.
|
| + """
|
| + cookies = request.cookies or {}
|
| +
|
| + # Bootstrap CookieJar.
|
| + if not isinstance(cookies, cookielib.CookieJar):
|
| + cookies = cookiejar_from_dict(cookies)
|
| +
|
| + # Merge with session cookies
|
| + merged_cookies = RequestsCookieJar()
|
| + merged_cookies.update(self.cookies)
|
| + merged_cookies.update(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,
|
| + 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_setting(request.hooks, self.hooks),
|
| + )
|
| + return p
|
| +
|
| def request(self, method, url,
|
| params=None,
|
| data=None,
|
| @@ -265,20 +308,22 @@ class Session(SessionRedirectMixin):
|
| :param cert: (optional) if String, path to ssl client cert file (.pem).
|
| If Tuple, ('cert', 'key') pair.
|
| """
|
| + # Create the Request.
|
| + req = Request(
|
| + method = method.upper(),
|
| + url = url,
|
| + headers = headers,
|
| + files = files,
|
| + data = data or {},
|
| + params = params or {},
|
| + auth = auth,
|
| + cookies = cookies,
|
| + hooks = hooks,
|
| + )
|
| + prep = self.prepare_request(req)
|
|
|
| - cookies = cookies or {}
|
| proxies = proxies or {}
|
|
|
| - # Bootstrap CookieJar.
|
| - if not isinstance(cookies, cookielib.CookieJar):
|
| - cookies = cookiejar_from_dict(cookies)
|
| -
|
| - # Merge with session cookies
|
| - merged_cookies = RequestsCookieJar()
|
| - merged_cookies.update(self.cookies)
|
| - merged_cookies.update(cookies)
|
| - cookies = merged_cookies
|
| -
|
| # Gather clues from the surrounding environment.
|
| if self.trust_env:
|
| # Set environment's proxies.
|
| @@ -286,10 +331,6 @@ class Session(SessionRedirectMixin):
|
| for (k, v) in env_proxies.items():
|
| proxies.setdefault(k, v)
|
|
|
| - # Set environment's basic authentication.
|
| - if not auth:
|
| - auth = get_netrc_auth(url)
|
| -
|
| # Look for configuration.
|
| if not verify and verify is not False:
|
| verify = os.environ.get('REQUESTS_CA_BUNDLE')
|
| @@ -299,30 +340,11 @@ class Session(SessionRedirectMixin):
|
| verify = os.environ.get('CURL_CA_BUNDLE')
|
|
|
| # Merge all the kwargs.
|
| - params = merge_setting(params, self.params)
|
| - headers = merge_setting(headers, self.headers, dict_class=CaseInsensitiveDict)
|
| - auth = merge_setting(auth, self.auth)
|
| proxies = merge_setting(proxies, self.proxies)
|
| - hooks = merge_setting(hooks, self.hooks)
|
| stream = merge_setting(stream, self.stream)
|
| verify = merge_setting(verify, self.verify)
|
| cert = merge_setting(cert, self.cert)
|
|
|
| - # Create the Request.
|
| - req = Request()
|
| - req.method = method.upper()
|
| - req.url = url
|
| - req.headers = headers
|
| - req.files = files
|
| - req.data = data
|
| - req.params = params
|
| - req.auth = auth
|
| - req.cookies = cookies
|
| - req.hooks = hooks
|
| -
|
| - # Prepare the Request.
|
| - prep = req.prepare()
|
| -
|
| # Send the request.
|
| send_kwargs = {
|
| 'stream': stream,
|
| @@ -416,7 +438,7 @@ class Session(SessionRedirectMixin):
|
|
|
| # It's possible that users might accidentally send a Request object.
|
| # Guard against that specific failure case.
|
| - if getattr(request, 'prepare', None):
|
| + if not isinstance(request, PreparedRequest):
|
| raise ValueError('You can only send PreparedRequests.')
|
|
|
| # Set up variables needed for resolve_redirects and dispatching of
|
| @@ -443,6 +465,10 @@ class Session(SessionRedirectMixin):
|
| 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.
|
| @@ -467,7 +493,7 @@ class Session(SessionRedirectMixin):
|
| """Returns the appropriate connnection adapter for the given URL."""
|
| for (prefix, adapter) in self.adapters.items():
|
|
|
| - if url.startswith(prefix):
|
| + if url.lower().startswith(prefix):
|
| return adapter
|
|
|
| # Nothing matches :-/
|
| @@ -475,7 +501,7 @@ class Session(SessionRedirectMixin):
|
|
|
| def close(self):
|
| """Closes all adapters and as such the session"""
|
| - for _, v in self.adapters.items():
|
| + for v in self.adapters.values():
|
| v.close()
|
|
|
| def mount(self, prefix, adapter):
|
|
|