OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 | 2 |
3 """ | 3 """ |
4 requests.adapters | 4 requests.adapters |
5 ~~~~~~~~~~~~~~~~~ | 5 ~~~~~~~~~~~~~~~~~ |
6 | 6 |
7 This module contains the transport adapters that Requests uses to define | 7 This module contains the transport adapters that Requests uses to define |
8 and maintain connections. | 8 and maintain connections. |
9 """ | 9 """ |
10 | 10 |
11 import socket | 11 import socket |
12 | 12 |
13 from .models import Response | 13 from .models import Response |
14 from .packages.urllib3.poolmanager import PoolManager, ProxyManager | 14 from .packages.urllib3.poolmanager import PoolManager, proxy_from_url |
15 from .packages.urllib3.response import HTTPResponse | 15 from .packages.urllib3.response import HTTPResponse |
| 16 from .packages.urllib3.util import Timeout as TimeoutSauce |
16 from .compat import urlparse, basestring, urldefrag, unquote | 17 from .compat import urlparse, basestring, urldefrag, unquote |
17 from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers, | 18 from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers, |
18 prepend_scheme_if_needed, get_auth_from_url) | 19 except_on_missing_scheme, get_auth_from_url) |
19 from .structures import CaseInsensitiveDict | 20 from .structures import CaseInsensitiveDict |
20 from .packages.urllib3.exceptions import MaxRetryError | 21 from .packages.urllib3.exceptions import MaxRetryError |
21 from .packages.urllib3.exceptions import TimeoutError | 22 from .packages.urllib3.exceptions import TimeoutError |
22 from .packages.urllib3.exceptions import SSLError as _SSLError | 23 from .packages.urllib3.exceptions import SSLError as _SSLError |
23 from .packages.urllib3.exceptions import HTTPError as _HTTPError | 24 from .packages.urllib3.exceptions import HTTPError as _HTTPError |
24 from .cookies import extract_cookies_to_jar | 25 from .cookies import extract_cookies_to_jar |
25 from .exceptions import ConnectionError, Timeout, SSLError | 26 from .exceptions import ConnectionError, Timeout, SSLError |
26 from .auth import _basic_auth_str | 27 from .auth import _basic_auth_str |
27 | 28 |
28 DEFAULT_POOLBLOCK = False | 29 DEFAULT_POOLBLOCK = False |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 >>> s.mount('http://', a) | 65 >>> s.mount('http://', a) |
65 """ | 66 """ |
66 __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', | 67 __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', |
67 '_pool_block'] | 68 '_pool_block'] |
68 | 69 |
69 def __init__(self, pool_connections=DEFAULT_POOLSIZE, | 70 def __init__(self, pool_connections=DEFAULT_POOLSIZE, |
70 pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, | 71 pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, |
71 pool_block=DEFAULT_POOLBLOCK): | 72 pool_block=DEFAULT_POOLBLOCK): |
72 self.max_retries = max_retries | 73 self.max_retries = max_retries |
73 self.config = {} | 74 self.config = {} |
| 75 self.proxy_manager = {} |
74 | 76 |
75 super(HTTPAdapter, self).__init__() | 77 super(HTTPAdapter, self).__init__() |
76 | 78 |
77 self._pool_connections = pool_connections | 79 self._pool_connections = pool_connections |
78 self._pool_maxsize = pool_maxsize | 80 self._pool_maxsize = pool_maxsize |
79 self._pool_block = pool_block | 81 self._pool_block = pool_block |
80 | 82 |
81 self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) | 83 self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) |
82 | 84 |
83 def __getstate__(self): | 85 def __getstate__(self): |
(...skipping 27 matching lines...) Expand all Loading... |
111 def cert_verify(self, conn, url, verify, cert): | 113 def cert_verify(self, conn, url, verify, cert): |
112 """Verify a SSL certificate. This method should not be called from user | 114 """Verify a SSL certificate. This method should not be called from user |
113 code, and is only exposed for use when subclassing the | 115 code, and is only exposed for use when subclassing the |
114 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. | 116 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. |
115 | 117 |
116 :param conn: The urllib3 connection object associated with the cert. | 118 :param conn: The urllib3 connection object associated with the cert. |
117 :param url: The requested URL. | 119 :param url: The requested URL. |
118 :param verify: Whether we should actually verify the certificate. | 120 :param verify: Whether we should actually verify the certificate. |
119 :param cert: The SSL certificate to verify. | 121 :param cert: The SSL certificate to verify. |
120 """ | 122 """ |
121 if url.startswith('https') and verify: | 123 if url.lower().startswith('https') and verify: |
122 | 124 |
123 cert_loc = None | 125 cert_loc = None |
124 | 126 |
125 # Allow self-specified cert location. | 127 # Allow self-specified cert location. |
126 if verify is not True: | 128 if verify is not True: |
127 cert_loc = verify | 129 cert_loc = verify |
128 | 130 |
129 if not cert_loc: | 131 if not cert_loc: |
130 cert_loc = DEFAULT_CA_BUNDLE_PATH | 132 cert_loc = DEFAULT_CA_BUNDLE_PATH |
131 | 133 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 | 179 |
178 # Give the Response some context. | 180 # Give the Response some context. |
179 response.request = req | 181 response.request = req |
180 response.connection = self | 182 response.connection = self |
181 | 183 |
182 return response | 184 return response |
183 | 185 |
184 def get_connection(self, url, proxies=None): | 186 def get_connection(self, url, proxies=None): |
185 """Returns a urllib3 connection for the given URL. This should not be | 187 """Returns a urllib3 connection for the given URL. This should not be |
186 called from user code, and is only exposed for use when subclassing the | 188 called from user code, and is only exposed for use when subclassing the |
187 :class:`HTTPAdapter <reqeusts.adapters.HTTPAdapter>`. | 189 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. |
188 | 190 |
189 :param url: The URL to connect to. | 191 :param url: The URL to connect to. |
190 :param proxies: (optional) A Requests-style dictionary of proxies used o
n this request. | 192 :param proxies: (optional) A Requests-style dictionary of proxies used o
n this request. |
191 """ | 193 """ |
192 proxies = proxies or {} | 194 proxies = proxies or {} |
193 proxy = proxies.get(urlparse(url).scheme) | 195 proxy = proxies.get(urlparse(url.lower()).scheme) |
194 | 196 |
195 if proxy: | 197 if proxy: |
196 proxy = prepend_scheme_if_needed(proxy, urlparse(url).scheme) | 198 except_on_missing_scheme(proxy) |
197 conn = ProxyManager(self.poolmanager.connection_from_url(proxy)) | 199 proxy_headers = self.proxy_headers(proxy) |
| 200 |
| 201 if not proxy in self.proxy_manager: |
| 202 self.proxy_manager[proxy] = proxy_from_url( |
| 203 proxy, |
| 204 proxy_headers=proxy_headers) |
| 205 |
| 206 conn = self.proxy_manager[proxy].connection_from_url(url) |
198 else: | 207 else: |
199 conn = self.poolmanager.connection_from_url(url) | 208 conn = self.poolmanager.connection_from_url(url.lower()) |
200 | 209 |
201 return conn | 210 return conn |
202 | 211 |
203 def close(self): | 212 def close(self): |
204 """Disposes of any internal state. | 213 """Disposes of any internal state. |
205 | 214 |
206 Currently, this just closes the PoolManager, which closes pooled | 215 Currently, this just closes the PoolManager, which closes pooled |
207 connections. | 216 connections. |
208 """ | 217 """ |
209 self.poolmanager.clear() | 218 self.poolmanager.clear() |
210 | 219 |
211 def request_url(self, request, proxies): | 220 def request_url(self, request, proxies): |
212 """Obtain the url to use when making the final request. | 221 """Obtain the url to use when making the final request. |
213 | 222 |
214 If the message is being sent through a proxy, the full URL has to be | 223 If the message is being sent through a proxy, the full URL has to be |
215 used. Otherwise, we should only use the path portion of the URL. | 224 used. Otherwise, we should only use the path portion of the URL. |
216 | 225 |
217 This shoudl not be called from user code, and is only exposed for use | 226 This should not be called from user code, and is only exposed for use |
218 when subclassing the | 227 when subclassing the |
219 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. | 228 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. |
220 | 229 |
221 :param request: The :class:`PreparedRequest <PreparedRequest>` being sen
t. | 230 :param request: The :class:`PreparedRequest <PreparedRequest>` being sen
t. |
222 :param proxies: A dictionary of schemes to proxy URLs. | 231 :param proxies: A dictionary of schemes to proxy URLs. |
223 """ | 232 """ |
224 proxies = proxies or {} | 233 proxies = proxies or {} |
225 proxy = proxies.get(urlparse(request.url).scheme) | 234 proxy = proxies.get(urlparse(request.url).scheme) |
226 | 235 |
227 if proxy: | 236 if proxy: |
228 url, _ = urldefrag(request.url) | 237 url, _ = urldefrag(request.url) |
229 else: | 238 else: |
230 url = request.path_url | 239 url = request.path_url |
231 | 240 |
232 return url | 241 return url |
233 | 242 |
234 def add_headers(self, request, **kwargs): | 243 def add_headers(self, request, **kwargs): |
235 """Add any headers needed by the connection. Currently this adds a | 244 """Add any headers needed by the connection. As of v2.0 this does |
236 Proxy-Authorization header. | 245 nothing by default, but is left for overriding by users that subclass |
| 246 the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. |
237 | 247 |
238 This should not be called from user code, and is only exposed for use | 248 This should not be called from user code, and is only exposed for use |
239 when subclassing the | 249 when subclassing the |
240 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. | 250 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. |
241 | 251 |
242 :param request: The :class:`PreparedRequest <PreparedRequest>` to add he
aders to. | 252 :param request: The :class:`PreparedRequest <PreparedRequest>` to add he
aders to. |
243 :param kwargs: The keyword arguments from the call to send(). | 253 :param kwargs: The keyword arguments from the call to send(). |
244 """ | 254 """ |
245 proxies = kwargs.get('proxies', {}) | 255 pass |
246 | 256 |
247 if proxies is None: | 257 def proxy_headers(self, proxy): |
248 proxies = {} | 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. |
249 | 262 |
250 proxy = proxies.get(urlparse(request.url).scheme) | 263 This should not be called from user code, and is only exposed for use |
| 264 when subclassing the |
| 265 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. |
| 266 |
| 267 :param proxies: The url of the proxy being used for this request. |
| 268 :param kwargs: Optional additional keyword arguments. |
| 269 """ |
| 270 headers = {} |
251 username, password = get_auth_from_url(proxy) | 271 username, password = get_auth_from_url(proxy) |
252 | 272 |
253 if username and password: | 273 if username and password: |
254 # Proxy auth usernames and passwords will be urlencoded, we need | 274 # Proxy auth usernames and passwords will be urlencoded, we need |
255 # to decode them. | 275 # to decode them. |
256 username = unquote(username) | 276 username = unquote(username) |
257 password = unquote(password) | 277 password = unquote(password) |
258 request.headers['Proxy-Authorization'] = _basic_auth_str(username, | 278 headers['Proxy-Authorization'] = _basic_auth_str(username, |
259 password) | 279 password) |
| 280 |
| 281 return headers |
260 | 282 |
261 def send(self, request, stream=False, timeout=None, verify=True, cert=None,
proxies=None): | 283 def send(self, request, stream=False, timeout=None, verify=True, cert=None,
proxies=None): |
262 """Sends PreparedRequest object. Returns Response object. | 284 """Sends PreparedRequest object. Returns Response object. |
263 | 285 |
264 :param request: The :class:`PreparedRequest <PreparedRequest>` being sen
t. | 286 :param request: The :class:`PreparedRequest <PreparedRequest>` being sen
t. |
265 :param stream: (optional) Whether to stream the request content. | 287 :param stream: (optional) Whether to stream the request content. |
266 :param timeout: (optional) The timeout on the request. | 288 :param timeout: (optional) The timeout on the request. |
267 :param verify: (optional) Whether to verify SSL certificates. | 289 :param verify: (optional) Whether to verify SSL certificates. |
268 :param vert: (optional) Any user-provided SSL certificate to be trusted. | 290 :param vert: (optional) Any user-provided SSL certificate to be trusted. |
269 :param proxies: (optional) The proxies dictionary to apply to the reques
t. | 291 :param proxies: (optional) The proxies dictionary to apply to the reques
t. |
270 """ | 292 """ |
271 | 293 |
272 conn = self.get_connection(request.url, proxies) | 294 conn = self.get_connection(request.url, proxies) |
273 | 295 |
274 self.cert_verify(conn, request.url, verify, cert) | 296 self.cert_verify(conn, request.url, verify, cert) |
275 url = self.request_url(request, proxies) | 297 url = self.request_url(request, proxies) |
276 self.add_headers(request, proxies=proxies) | 298 self.add_headers(request) |
277 | 299 |
278 chunked = not (request.body is None or 'Content-Length' in request.heade
rs) | 300 chunked = not (request.body is None or 'Content-Length' in request.heade
rs) |
279 | 301 |
| 302 if stream: |
| 303 timeout = TimeoutSauce(connect=timeout) |
| 304 else: |
| 305 timeout = TimeoutSauce(connect=timeout, read=timeout) |
| 306 |
280 try: | 307 try: |
281 if not chunked: | 308 if not chunked: |
282 resp = conn.urlopen( | 309 resp = conn.urlopen( |
283 method=request.method, | 310 method=request.method, |
284 url=url, | 311 url=url, |
285 body=request.body, | 312 body=request.body, |
286 headers=request.headers, | 313 headers=request.headers, |
287 redirect=False, | 314 redirect=False, |
288 assert_same_host=False, | 315 assert_same_host=False, |
289 preload_content=False, | 316 preload_content=False, |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 raise Timeout(e) | 360 raise Timeout(e) |
334 else: | 361 else: |
335 raise | 362 raise |
336 | 363 |
337 r = self.build_response(request, resp) | 364 r = self.build_response(request, resp) |
338 | 365 |
339 if not stream: | 366 if not stream: |
340 r.content | 367 r.content |
341 | 368 |
342 return r | 369 return r |
OLD | NEW |