diff options
Diffstat (limited to 'requests/adapters.py')
-rw-r--r-- | requests/adapters.py | 63 |
1 files changed, 45 insertions, 18 deletions
diff --git a/requests/adapters.py b/requests/adapters.py index 98b7317..d557b74 100644 --- a/requests/adapters.py +++ b/requests/adapters.py @@ -11,11 +11,12 @@ and maintain connections. import socket from .models import Response -from .packages.urllib3.poolmanager import PoolManager, ProxyManager +from .packages.urllib3.poolmanager import PoolManager, proxy_from_url from .packages.urllib3.response import HTTPResponse +from .packages.urllib3.util import Timeout as TimeoutSauce from .compat import urlparse, basestring, urldefrag, unquote from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers, - prepend_scheme_if_needed, get_auth_from_url) + except_on_missing_scheme, get_auth_from_url) from .structures import CaseInsensitiveDict from .packages.urllib3.exceptions import MaxRetryError from .packages.urllib3.exceptions import TimeoutError @@ -71,6 +72,7 @@ class HTTPAdapter(BaseAdapter): pool_block=DEFAULT_POOLBLOCK): self.max_retries = max_retries self.config = {} + self.proxy_manager = {} super(HTTPAdapter, self).__init__() @@ -118,7 +120,7 @@ class HTTPAdapter(BaseAdapter): :param verify: Whether we should actually verify the certificate. :param cert: The SSL certificate to verify. """ - if url.startswith('https') and verify: + if url.lower().startswith('https') and verify: cert_loc = None @@ -184,19 +186,26 @@ class HTTPAdapter(BaseAdapter): def get_connection(self, url, proxies=None): """Returns a urllib3 connection for the given URL. This should not be called from user code, and is only exposed for use when subclassing the - :class:`HTTPAdapter <reqeusts.adapters.HTTPAdapter>`. + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. :param url: The URL to connect to. :param proxies: (optional) A Requests-style dictionary of proxies used on this request. """ proxies = proxies or {} - proxy = proxies.get(urlparse(url).scheme) + proxy = proxies.get(urlparse(url.lower()).scheme) if proxy: - proxy = prepend_scheme_if_needed(proxy, urlparse(url).scheme) - conn = ProxyManager(self.poolmanager.connection_from_url(proxy)) + except_on_missing_scheme(proxy) + proxy_headers = self.proxy_headers(proxy) + + if not proxy in self.proxy_manager: + self.proxy_manager[proxy] = proxy_from_url( + proxy, + proxy_headers=proxy_headers) + + conn = self.proxy_manager[proxy].connection_from_url(url) else: - conn = self.poolmanager.connection_from_url(url) + conn = self.poolmanager.connection_from_url(url.lower()) return conn @@ -214,7 +223,7 @@ class HTTPAdapter(BaseAdapter): If the message is being sent through a proxy, the full URL has to be used. Otherwise, we should only use the path portion of the URL. - This shoudl not be called from user code, and is only exposed for use + This should not be called from user code, and is only exposed for use when subclassing the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. @@ -232,8 +241,9 @@ class HTTPAdapter(BaseAdapter): return url def add_headers(self, request, **kwargs): - """Add any headers needed by the connection. Currently this adds a - Proxy-Authorization header. + """Add any headers needed by the connection. As of v2.0 this does + nothing by default, but is left for overriding by users that subclass + the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. This should not be called from user code, and is only exposed for use when subclassing the @@ -242,12 +252,22 @@ class HTTPAdapter(BaseAdapter): :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to. :param kwargs: The keyword arguments from the call to send(). """ - proxies = kwargs.get('proxies', {}) + pass - if proxies is None: - proxies = {} + def proxy_headers(self, proxy): + """Returns a dictionary of the headers to add to any request sent + through a proxy. This works with urllib3 magic to ensure that they are + correctly sent to the proxy, rather than in a tunnelled request if + CONNECT is being used. - proxy = proxies.get(urlparse(request.url).scheme) + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param proxies: The url of the proxy being used for this request. + :param kwargs: Optional additional keyword arguments. + """ + headers = {} username, password = get_auth_from_url(proxy) if username and password: @@ -255,8 +275,10 @@ class HTTPAdapter(BaseAdapter): # to decode them. username = unquote(username) password = unquote(password) - request.headers['Proxy-Authorization'] = _basic_auth_str(username, - password) + headers['Proxy-Authorization'] = _basic_auth_str(username, + password) + + return headers def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): """Sends PreparedRequest object. Returns Response object. @@ -273,10 +295,15 @@ class HTTPAdapter(BaseAdapter): self.cert_verify(conn, request.url, verify, cert) url = self.request_url(request, proxies) - self.add_headers(request, proxies=proxies) + self.add_headers(request) chunked = not (request.body is None or 'Content-Length' in request.headers) + if stream: + timeout = TimeoutSauce(connect=timeout) + else: + timeout = TimeoutSauce(connect=timeout, read=timeout) + try: if not chunked: resp = conn.urlopen( |