1 # -*- coding: utf-8 -*-
7 This module contains the transport adapters that Requests uses to define
8 and maintain connections.
13 from .models import Response
14 from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
15 from .packages.urllib3.response import HTTPResponse
16 from .packages.urllib3.util import Timeout
17 from .compat import urlparse, basestring, urldefrag, unquote
18 from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
19 except_on_missing_scheme, get_auth_from_url)
20 from .structures import CaseInsensitiveDict
21 from .packages.urllib3.exceptions import MaxRetryError
22 from .packages.urllib3.exceptions import TimeoutError
23 from .packages.urllib3.exceptions import SSLError as _SSLError
24 from .packages.urllib3.exceptions import HTTPError as _HTTPError
25 from .cookies import extract_cookies_to_jar
26 from .exceptions import ConnectionError, Timeout, SSLError
27 from .auth import _basic_auth_str
29 DEFAULT_POOLBLOCK = False
34 class BaseAdapter(object):
35 """The Base Transport Adapter"""
38 super(BaseAdapter, self).__init__()
41 raise NotImplementedError
44 raise NotImplementedError
47 class HTTPAdapter(BaseAdapter):
48 """The built-in HTTP Adapter for urllib3.
50 Provides a general-case interface for Requests sessions to contact HTTP and
51 HTTPS urls by implementing the Transport Adapter interface. This class will
52 usually be created by the :class:`Session <Session>` class under the
55 :param pool_connections: The number of urllib3 connection pools to cache.
56 :param pool_maxsize: The maximum number of connections to save in the pool.
57 :param max_retries: The maximum number of retries each connection should attempt.
58 :param pool_block: Whether the connection pool should block for connections.
63 >>> s = requests.Session()
64 >>> a = requests.adapters.HTTPAdapter()
65 >>> s.mount('http://', a)
67 __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize',
70 def __init__(self, pool_connections=DEFAULT_POOLSIZE,
71 pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES,
72 pool_block=DEFAULT_POOLBLOCK):
73 self.max_retries = max_retries
75 self.proxy_manager = {}
77 super(HTTPAdapter, self).__init__()
79 self._pool_connections = pool_connections
80 self._pool_maxsize = pool_maxsize
81 self._pool_block = pool_block
83 self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
85 def __getstate__(self):
86 return dict((attr, getattr(self, attr, None)) for attr in
89 def __setstate__(self, state):
90 for attr, value in state.items():
91 setattr(self, attr, value)
93 self.init_poolmanager(self._pool_connections, self._pool_maxsize,
94 block=self._pool_block)
96 def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK):
97 """Initializes a urllib3 PoolManager. This method should not be called
98 from user code, and is only exposed for use when subclassing the
99 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
101 :param connections: The number of urllib3 connection pools to cache.
102 :param maxsize: The maximum number of connections to save in the pool.
103 :param block: Block when no free connections are available.
105 # save these values for pickling
106 self._pool_connections = connections
107 self._pool_maxsize = maxsize
108 self._pool_block = block
110 self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize,
113 def cert_verify(self, conn, url, verify, cert):
114 """Verify a SSL certificate. This method should not be called from user
115 code, and is only exposed for use when subclassing the
116 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
118 :param conn: The urllib3 connection object associated with the cert.
119 :param url: The requested URL.
120 :param verify: Whether we should actually verify the certificate.
121 :param cert: The SSL certificate to verify.
123 if url.lower().startswith('https') and verify:
127 # Allow self-specified cert location.
128 if verify is not True:
132 cert_loc = DEFAULT_CA_BUNDLE_PATH
135 raise Exception("Could not find a suitable SSL CA certificate bundle.")
137 conn.cert_reqs = 'CERT_REQUIRED'
138 conn.ca_certs = cert_loc
140 conn.cert_reqs = 'CERT_NONE'
144 if not isinstance(cert, basestring):
145 conn.cert_file = cert[0]
146 conn.key_file = cert[1]
148 conn.cert_file = cert
150 def build_response(self, req, resp):
151 """Builds a :class:`Response <requests.Response>` object from a urllib3
152 response. This should not be called from user code, and is only exposed
153 for use when subclassing the
154 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`
156 :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response.
157 :param resp: The urllib3 response object.
159 response = Response()
161 # Fallback to None if there's no status_code, for whatever reason.
162 response.status_code = getattr(resp, 'status', None)
164 # Make headers case-insensitive.
165 response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {}))
168 response.encoding = get_encoding_from_headers(response.headers)
170 response.reason = response.raw.reason
172 if isinstance(req.url, bytes):
173 response.url = req.url.decode('utf-8')
175 response.url = req.url
177 # Add new cookies from the server.
178 extract_cookies_to_jar(response.cookies, req, resp)
180 # Give the Response some context.
181 response.request = req
182 response.connection = self
186 def get_connection(self, url, proxies=None):
187 """Returns a urllib3 connection for the given URL. This should not be
188 called from user code, and is only exposed for use when subclassing the
189 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
191 :param url: The URL to connect to.
192 :param proxies: (optional) A Requests-style dictionary of proxies used on this request.
194 proxies = proxies or {}
195 proxy = proxies.get(urlparse(url.lower()).scheme)
198 except_on_missing_scheme(proxy)
199 proxy_headers = self.proxy_headers(proxy)
201 if not proxy in self.proxy_manager:
202 self.proxy_manager[proxy] = proxy_from_url(
204 proxy_headers=proxy_headers)
206 conn = self.proxy_manager[proxy].connection_from_url(url)
208 conn = self.poolmanager.connection_from_url(url.lower())
213 """Disposes of any internal state.
215 Currently, this just closes the PoolManager, which closes pooled
218 self.poolmanager.clear()
220 def request_url(self, request, proxies):
221 """Obtain the url to use when making the final request.
223 If the message is being sent through a proxy, the full URL has to be
224 used. Otherwise, we should only use the path portion of the URL.
226 This should not be called from user code, and is only exposed for use
228 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
230 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
231 :param proxies: A dictionary of schemes to proxy URLs.
233 proxies = proxies or {}
234 proxy = proxies.get(urlparse(request.url).scheme)
237 url, _ = urldefrag(request.url)
239 url = request.path_url
243 def add_headers(self, request, **kwargs):
244 """Add any headers needed by the connection. As of v2.0 this does
245 nothing by default, but is left for overriding by users that subclass
246 the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
248 This should not be called from user code, and is only exposed for use
250 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
252 :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to.
253 :param kwargs: The keyword arguments from the call to send().
257 def proxy_headers(self, proxy):
258 """Returns a dictionary of the headers to add to any request sent
259 through a proxy. This works with urllib3 magic to ensure that they are
260 correctly sent to the proxy, rather than in a tunnelled request if
261 CONNECT is being used.
263 This should not be called from user code, and is only exposed for use
265 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
267 :param proxies: The url of the proxy being used for this request.
268 :param kwargs: Optional additional keyword arguments.
271 username, password = get_auth_from_url(proxy)
273 if username and password:
274 # Proxy auth usernames and passwords will be urlencoded, we need
276 username = unquote(username)
277 password = unquote(password)
278 headers['Proxy-Authorization'] = _basic_auth_str(username,
283 def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
284 """Sends PreparedRequest object. Returns Response object.
286 :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
287 :param stream: (optional) Whether to stream the request content.
288 :param timeout: (optional) The timeout on the request.
289 :param verify: (optional) Whether to verify SSL certificates.
290 :param vert: (optional) Any user-provided SSL certificate to be trusted.
291 :param proxies: (optional) The proxies dictionary to apply to the request.
294 conn = self.get_connection(request.url, proxies)
296 self.cert_verify(conn, request.url, verify, cert)
297 url = self.request_url(request, proxies)
298 self.add_headers(request)
300 chunked = not (request.body is None or 'Content-Length' in request.headers)
303 timeout = Timeout(connect=timeout)
305 timeout = Timeout(connect=timeout, read=timeout)
310 method=request.method,
313 headers=request.headers,
315 assert_same_host=False,
316 preload_content=False,
317 decode_content=False,
318 retries=self.max_retries,
324 if hasattr(conn, 'proxy_pool'):
325 conn = conn.proxy_pool
327 low_conn = conn._get_conn(timeout=timeout)
328 low_conn.putrequest(request.method, url, skip_accept_encoding=True)
330 for header, value in request.headers.items():
331 low_conn.putheader(header, value)
333 low_conn.endheaders()
335 for i in request.body:
336 low_conn.send(hex(len(i))[2:].encode('utf-8'))
337 low_conn.send(b'\r\n')
339 low_conn.send(b'\r\n')
340 low_conn.send(b'0\r\n\r\n')
342 r = low_conn.getresponse()
343 resp = HTTPResponse.from_httplib(r,
346 preload_content=False,
350 except socket.error as sockerr:
351 raise ConnectionError(sockerr)
353 except MaxRetryError as e:
354 raise ConnectionError(e)
356 except (_SSLError, _HTTPError) as e:
357 if isinstance(e, _SSLError):
359 elif isinstance(e, TimeoutError):
364 r = self.build_response(request, resp)