|
12 | 12 | from collections import Mapping |
13 | 13 | from datetime import datetime |
14 | 14 |
|
| 15 | +from .auth import _basic_auth_str |
15 | 16 | from .compat import cookielib, OrderedDict, urljoin, urlparse, builtin_str |
16 | 17 | from .cookies import ( |
17 | 18 | cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) |
|
23 | 24 |
|
24 | 25 | from .adapters import HTTPAdapter |
25 | 26 |
|
26 | | -from .utils import requote_uri, get_environ_proxies, get_netrc_auth |
| 27 | +from .utils import ( |
| 28 | + requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, |
| 29 | + get_auth_from_url |
| 30 | +) |
27 | 31 |
|
28 | 32 | from .status_codes import codes |
29 | 33 |
|
@@ -154,6 +158,8 @@ def resolve_redirects(self, resp, req, stream=False, timeout=None, |
154 | 158 | prepared_request._cookies.update(self.cookies) |
155 | 159 | prepared_request.prepare_cookies(prepared_request._cookies) |
156 | 160 |
|
| 161 | + # Rebuild auth and proxy information. |
| 162 | + proxies = self.rebuild_proxies(prepared_request, proxies) |
157 | 163 | self.rebuild_auth(prepared_request, resp) |
158 | 164 |
|
159 | 165 | resp = self.send( |
@@ -196,6 +202,50 @@ def rebuild_auth(self, prepared_request, response): |
196 | 202 |
|
197 | 203 | return |
198 | 204 |
|
| 205 | + def rebuild_proxies(self, prepared_request, proxies): |
| 206 | + """ |
| 207 | + This method re-evaluates the proxy configuration by considering the |
| 208 | + environment variables. If we are redirected to a URL covered by |
| 209 | + NO_PROXY, we strip the proxy configuration. Otherwise, we set missing |
| 210 | + proxy keys for this URL (in case they were stripped by a previous |
| 211 | + redirect). |
| 212 | +
|
| 213 | + This method also replaces the Proxy-Authorization header where |
| 214 | + necessary. |
| 215 | + """ |
| 216 | + headers = prepared_request.headers |
| 217 | + url = prepared_request.url |
| 218 | + new_proxies = {} |
| 219 | + |
| 220 | + # Consider proxies. First evaluate the new proxy config. If we are |
| 221 | + # being redirected to a host on the NO_PROXY list then we want to |
| 222 | + # remove the proxy dictionary entirely. Otherwise, if there's a relevant |
| 223 | + # environment proxy, set it if we don't already have a proxy to go to. |
| 224 | + if not should_bypass_proxies(url): |
| 225 | + environ_proxies = get_environ_proxies(url) |
| 226 | + scheme = urlparse(url).scheme |
| 227 | + |
| 228 | + try: |
| 229 | + new_proxies.setdefault(scheme, environ_proxies[scheme]) |
| 230 | + except KeyError: |
| 231 | + pass |
| 232 | + |
| 233 | + # If there's a proxy-authorization header present, remove it, then add |
| 234 | + # a new one (potentially re-adding the one we just removed). |
| 235 | + if 'Proxy-Authorization' in headers: |
| 236 | + del headers['Proxy-Authorization'] |
| 237 | + |
| 238 | + try: |
| 239 | + username, password = get_auth_from_url(new_proxies[scheme]) |
| 240 | + if username and password: |
| 241 | + headers['Proxy-Authorization'] = _basic_auth_str( |
| 242 | + username, password |
| 243 | + ) |
| 244 | + except KeyError: |
| 245 | + pass |
| 246 | + |
| 247 | + return new_proxies |
| 248 | + |
199 | 249 |
|
200 | 250 | class Session(SessionRedirectMixin): |
201 | 251 | """A Requests session. |
|
0 commit comments