aboutsummaryrefslogtreecommitdiff
path: root/requests/adapters.py
diff options
context:
space:
mode:
Diffstat (limited to 'requests/adapters.py')
-rw-r--r--requests/adapters.py63
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(