Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/requests/packages/urllib3/poolmanager.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 import logging | |
2 | |
3 try: # Python 3 | |
4 from urllib.parse import urljoin | |
5 except ImportError: | |
6 from urlparse import urljoin | |
7 | |
8 from ._collections import RecentlyUsedContainer | |
9 from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool | |
10 from .connectionpool import port_by_scheme | |
11 from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown | |
12 from .request import RequestMethods | |
13 from .util.url import parse_url | |
14 from .util.retry import Retry | |
15 | |
16 | |
17 __all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url'] | |
18 | |
19 | |
20 pool_classes_by_scheme = { | |
21 'http': HTTPConnectionPool, | |
22 'https': HTTPSConnectionPool, | |
23 } | |
24 | |
25 log = logging.getLogger(__name__) | |
26 | |
27 SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs', | |
28 'ssl_version') | |
29 | |
30 | |
31 class PoolManager(RequestMethods): | |
32 """ | |
33 Allows for arbitrary requests while transparently keeping track of | |
34 necessary connection pools for you. | |
35 | |
36 :param num_pools: | |
37 Number of connection pools to cache before discarding the least | |
38 recently used pool. | |
39 | |
40 :param headers: | |
41 Headers to include with all requests, unless other headers are given | |
42 explicitly. | |
43 | |
44 :param \**connection_pool_kw: | |
45 Additional parameters are used to create fresh | |
46 :class:`urllib3.connectionpool.ConnectionPool` instances. | |
47 | |
48 Example:: | |
49 | |
50 >>> manager = PoolManager(num_pools=2) | |
51 >>> r = manager.request('GET', 'http://google.com/') | |
52 >>> r = manager.request('GET', 'http://google.com/mail') | |
53 >>> r = manager.request('GET', 'http://yahoo.com/') | |
54 >>> len(manager.pools) | |
55 2 | |
56 | |
57 """ | |
58 | |
59 proxy = None | |
60 | |
61 def __init__(self, num_pools=10, headers=None, **connection_pool_kw): | |
62 RequestMethods.__init__(self, headers) | |
63 self.connection_pool_kw = connection_pool_kw | |
64 self.pools = RecentlyUsedContainer(num_pools, | |
65 dispose_func=lambda p: p.close()) | |
66 | |
67 def __enter__(self): | |
68 return self | |
69 | |
70 def __exit__(self, exc_type, exc_val, exc_tb): | |
71 self.clear() | |
72 # Return False to re-raise any potential exceptions | |
73 return False | |
74 | |
75 def _new_pool(self, scheme, host, port): | |
76 """ | |
77 Create a new :class:`ConnectionPool` based on host, port and scheme. | |
78 | |
79 This method is used to actually create the connection pools handed out | |
80 by :meth:`connection_from_url` and companion methods. It is intended | |
81 to be overridden for customization. | |
82 """ | |
83 pool_cls = pool_classes_by_scheme[scheme] | |
84 kwargs = self.connection_pool_kw | |
85 if scheme == 'http': | |
86 kwargs = self.connection_pool_kw.copy() | |
87 for kw in SSL_KEYWORDS: | |
88 kwargs.pop(kw, None) | |
89 | |
90 return pool_cls(host, port, **kwargs) | |
91 | |
92 def clear(self): | |
93 """ | |
94 Empty our store of pools and direct them all to close. | |
95 | |
96 This will not affect in-flight connections, but they will not be | |
97 re-used after completion. | |
98 """ | |
99 self.pools.clear() | |
100 | |
101 def connection_from_host(self, host, port=None, scheme='http'): | |
102 """ | |
103 Get a :class:`ConnectionPool` based on the host, port, and scheme. | |
104 | |
105 If ``port`` isn't given, it will be derived from the ``scheme`` using | |
106 ``urllib3.connectionpool.port_by_scheme``. | |
107 """ | |
108 | |
109 if not host: | |
110 raise LocationValueError("No host specified.") | |
111 | |
112 scheme = scheme or 'http' | |
113 port = port or port_by_scheme.get(scheme, 80) | |
114 pool_key = (scheme, host, port) | |
115 | |
116 with self.pools.lock: | |
117 # If the scheme, host, or port doesn't match existing open | |
118 # connections, open a new ConnectionPool. | |
119 pool = self.pools.get(pool_key) | |
120 if pool: | |
121 return pool | |
122 | |
123 # Make a fresh ConnectionPool of the desired type | |
124 pool = self._new_pool(scheme, host, port) | |
125 self.pools[pool_key] = pool | |
126 | |
127 return pool | |
128 | |
129 def connection_from_url(self, url): | |
130 """ | |
131 Similar to :func:`urllib3.connectionpool.connection_from_url` but | |
132 doesn't pass any additional parameters to the | |
133 :class:`urllib3.connectionpool.ConnectionPool` constructor. | |
134 | |
135 Additional parameters are taken from the :class:`.PoolManager` | |
136 constructor. | |
137 """ | |
138 u = parse_url(url) | |
139 return self.connection_from_host(u.host, port=u.port, scheme=u.scheme) | |
140 | |
141 def urlopen(self, method, url, redirect=True, **kw): | |
142 """ | |
143 Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen` | |
144 with custom cross-host redirect logic and only sends the request-uri | |
145 portion of the ``url``. | |
146 | |
147 The given ``url`` parameter must be absolute, such that an appropriate | |
148 :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. | |
149 """ | |
150 u = parse_url(url) | |
151 conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) | |
152 | |
153 kw['assert_same_host'] = False | |
154 kw['redirect'] = False | |
155 if 'headers' not in kw: | |
156 kw['headers'] = self.headers | |
157 | |
158 if self.proxy is not None and u.scheme == "http": | |
159 response = conn.urlopen(method, url, **kw) | |
160 else: | |
161 response = conn.urlopen(method, u.request_uri, **kw) | |
162 | |
163 redirect_location = redirect and response.get_redirect_location() | |
164 if not redirect_location: | |
165 return response | |
166 | |
167 # Support relative URLs for redirecting. | |
168 redirect_location = urljoin(url, redirect_location) | |
169 | |
170 # RFC 7231, Section 6.4.4 | |
171 if response.status == 303: | |
172 method = 'GET' | |
173 | |
174 retries = kw.get('retries') | |
175 if not isinstance(retries, Retry): | |
176 retries = Retry.from_int(retries, redirect=redirect) | |
177 | |
178 try: | |
179 retries = retries.increment(method, url, response=response, _pool=conn) | |
180 except MaxRetryError: | |
181 if retries.raise_on_redirect: | |
182 raise | |
183 return response | |
184 | |
185 kw['retries'] = retries | |
186 kw['redirect'] = redirect | |
187 | |
188 log.info("Redirecting %s -> %s" % (url, redirect_location)) | |
189 return self.urlopen(method, redirect_location, **kw) | |
190 | |
191 | |
192 class ProxyManager(PoolManager): | |
193 """ | |
194 Behaves just like :class:`PoolManager`, but sends all requests through | |
195 the defined proxy, using the CONNECT method for HTTPS URLs. | |
196 | |
197 :param proxy_url: | |
198 The URL of the proxy to be used. | |
199 | |
200 :param proxy_headers: | |
201 A dictionary contaning headers that will be sent to the proxy. In case | |
202 of HTTP they are being sent with each request, while in the | |
203 HTTPS/CONNECT case they are sent only once. Could be used for proxy | |
204 authentication. | |
205 | |
206 Example: | |
207 >>> proxy = urllib3.ProxyManager('http://localhost:3128/') | |
208 >>> r1 = proxy.request('GET', 'http://google.com/') | |
209 >>> r2 = proxy.request('GET', 'http://httpbin.org/') | |
210 >>> len(proxy.pools) | |
211 1 | |
212 >>> r3 = proxy.request('GET', 'https://httpbin.org/') | |
213 >>> r4 = proxy.request('GET', 'https://twitter.com/') | |
214 >>> len(proxy.pools) | |
215 3 | |
216 | |
217 """ | |
218 | |
219 def __init__(self, proxy_url, num_pools=10, headers=None, | |
220 proxy_headers=None, **connection_pool_kw): | |
221 | |
222 if isinstance(proxy_url, HTTPConnectionPool): | |
223 proxy_url = '%s://%s:%i' % (proxy_url.scheme, proxy_url.host, | |
224 proxy_url.port) | |
225 proxy = parse_url(proxy_url) | |
226 if not proxy.port: | |
227 port = port_by_scheme.get(proxy.scheme, 80) | |
228 proxy = proxy._replace(port=port) | |
229 | |
230 if proxy.scheme not in ("http", "https"): | |
231 raise ProxySchemeUnknown(proxy.scheme) | |
232 | |
233 self.proxy = proxy | |
234 self.proxy_headers = proxy_headers or {} | |
235 | |
236 connection_pool_kw['_proxy'] = self.proxy | |
237 connection_pool_kw['_proxy_headers'] = self.proxy_headers | |
238 | |
239 super(ProxyManager, self).__init__( | |
240 num_pools, headers, **connection_pool_kw) | |
241 | |
242 def connection_from_host(self, host, port=None, scheme='http'): | |
243 if scheme == "https": | |
244 return super(ProxyManager, self).connection_from_host( | |
245 host, port, scheme) | |
246 | |
247 return super(ProxyManager, self).connection_from_host( | |
248 self.proxy.host, self.proxy.port, self.proxy.scheme) | |
249 | |
250 def _set_proxy_headers(self, url, headers=None): | |
251 """ | |
252 Sets headers needed by proxies: specifically, the Accept and Host | |
253 headers. Only sets headers not provided by the user. | |
254 """ | |
255 headers_ = {'Accept': '*/*'} | |
256 | |
257 netloc = parse_url(url).netloc | |
258 if netloc: | |
259 headers_['Host'] = netloc | |
260 | |
261 if headers: | |
262 headers_.update(headers) | |
263 return headers_ | |
264 | |
265 def urlopen(self, method, url, redirect=True, **kw): | |
266 "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." | |
267 u = parse_url(url) | |
268 | |
269 if u.scheme == "http": | |
270 # For proxied HTTPS requests, httplib sets the necessary headers | |
271 # on the CONNECT to the proxy. For HTTP, we'll definitely | |
272 # need to set 'Host' at the very least. | |
273 headers = kw.get('headers', self.headers) | |
274 kw['headers'] = self._set_proxy_headers(url, headers) | |
275 | |
276 return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) | |
277 | |
278 | |
279 def proxy_from_url(url, **kw): | |
280 return ProxyManager(proxy_url=url, **kw) |