Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: third_party/requests/adapters.py

Issue 24076010: Add 'requests' library to third_party. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/swarm_client
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 # -*- coding: utf-8 -*-
2
M-A Ruel 2013/09/12 16:28:01 This will blow up checklicense.py, dang.
3 """
4 requests.adapters
5 ~~~~~~~~~~~~~~~~~
6
7 This module contains the transport adapters that Requests uses to define
8 and maintain connections.
9 """
10
11 import socket
12
13 from .models import Response
14 from .packages.urllib3.poolmanager import PoolManager, ProxyManager
15 from .packages.urllib3.response import HTTPResponse
16 from .compat import urlparse, basestring, urldefrag, unquote
17 from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
18 prepend_scheme_if_needed, get_auth_from_url)
19 from .structures import CaseInsensitiveDict
20 from .packages.urllib3.exceptions import MaxRetryError
21 from .packages.urllib3.exceptions import TimeoutError
22 from .packages.urllib3.exceptions import SSLError as _SSLError
23 from .packages.urllib3.exceptions import HTTPError as _HTTPError
24 from .cookies import extract_cookies_to_jar
25 from .exceptions import ConnectionError, Timeout, SSLError
26 from .auth import _basic_auth_str
27
28 DEFAULT_POOLBLOCK = False
29 DEFAULT_POOLSIZE = 10
30 DEFAULT_RETRIES = 0
31
32
33 class BaseAdapter(object):
34 """The Base Transport Adapter"""
35
36 def __init__(self):
37 super(BaseAdapter, self).__init__()
38
39 def send(self):
40 raise NotImplementedError
41
42 def close(self):
43 raise NotImplementedError
44
45
46 class HTTPAdapter(BaseAdapter):
47 """The built-in HTTP Adapter for urllib3.
48
49 Provides a general-case interface for Requests sessions to contact HTTP and
50 HTTPS urls by implementing the Transport Adapter interface. This class will
51 usually be created by the :class:`Session <Session>` class under the
52 covers.
53
54 :param pool_connections: The number of urllib3 connection pools to cache.
55 :param pool_maxsize: The maximum number of connections to save in the pool.
56 :param max_retries: The maximum number of retries each connection should att empt.
57 :param pool_block: Whether the connection pool should block for connections.
58
59 Usage::
60
61 >>> import requests
62 >>> s = requests.Session()
63 >>> a = requests.adapters.HTTPAdapter()
64 >>> s.mount('http://', a)
65 """
66 __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize',
67 '_pool_block']
68
69 def __init__(self, pool_connections=DEFAULT_POOLSIZE,
70 pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES,
71 pool_block=DEFAULT_POOLBLOCK):
72 self.max_retries = max_retries
73 self.config = {}
74
75 super(HTTPAdapter, self).__init__()
76
77 self._pool_connections = pool_connections
78 self._pool_maxsize = pool_maxsize
79 self._pool_block = pool_block
80
81 self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
82
83 def __getstate__(self):
84 return dict((attr, getattr(self, attr, None)) for attr in
85 self.__attrs__)
86
87 def __setstate__(self, state):
88 for attr, value in state.items():
89 setattr(self, attr, value)
90
91 self.init_poolmanager(self._pool_connections, self._pool_maxsize,
92 block=self._pool_block)
93
94 def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK):
95 """Initializes a urllib3 PoolManager. This method should not be called
96 from user code, and is only exposed for use when subclassing the
97 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
98
99 :param connections: The number of urllib3 connection pools to cache.
100 :param maxsize: The maximum number of connections to save in the pool.
101 :param block: Block when no free connections are available.
102 """
103 # save these values for pickling
104 self._pool_connections = connections
105 self._pool_maxsize = maxsize
106 self._pool_block = block
107
108 self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize,
109 block=block)
110
111 def cert_verify(self, conn, url, verify, cert):
112 """Verify a SSL certificate. This method should not be called from user
113 code, and is only exposed for use when subclassing the
114 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
115
116 :param conn: The urllib3 connection object associated with the cert.
117 :param url: The requested URL.
118 :param verify: Whether we should actually verify the certificate.
119 :param cert: The SSL certificate to verify.
120 """
121 if url.startswith('https') and verify:
122
123 cert_loc = None
124
125 # Allow self-specified cert location.
126 if verify is not True:
127 cert_loc = verify
128
129 if not cert_loc:
130 cert_loc = DEFAULT_CA_BUNDLE_PATH
131
132 if not cert_loc:
133 raise Exception("Could not find a suitable SSL CA certificate bu ndle.")
134
135 conn.cert_reqs = 'CERT_REQUIRED'
136 conn.ca_certs = cert_loc
137 else:
138 conn.cert_reqs = 'CERT_NONE'
139 conn.ca_certs = None
140
141 if cert:
142 if not isinstance(cert, basestring):
143 conn.cert_file = cert[0]
144 conn.key_file = cert[1]
145 else:
146 conn.cert_file = cert
147
148 def build_response(self, req, resp):
149 """Builds a :class:`Response <requests.Response>` object from a urllib3
150 response. This should not be called from user code, and is only exposed
151 for use when subclassing the
152 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`
153
154 :param req: The :class:`PreparedRequest <PreparedRequest>` used to gener ate the response.
155 :param resp: The urllib3 response object.
156 """
157 response = Response()
158
159 # Fallback to None if there's no status_code, for whatever reason.
160 response.status_code = getattr(resp, 'status', None)
161
162 # Make headers case-insensitive.
163 response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {}))
164
165 # Set encoding.
166 response.encoding = get_encoding_from_headers(response.headers)
167 response.raw = resp
168 response.reason = response.raw.reason
169
170 if isinstance(req.url, bytes):
171 response.url = req.url.decode('utf-8')
172 else:
173 response.url = req.url
174
175 # Add new cookies from the server.
176 extract_cookies_to_jar(response.cookies, req, resp)
177
178 # Give the Response some context.
179 response.request = req
180 response.connection = self
181
182 return response
183
184 def get_connection(self, url, proxies=None):
185 """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
187 :class:`HTTPAdapter <reqeusts.adapters.HTTPAdapter>`.
188
189 :param url: The URL to connect to.
190 :param proxies: (optional) A Requests-style dictionary of proxies used o n this request.
191 """
192 proxies = proxies or {}
193 proxy = proxies.get(urlparse(url).scheme)
194
195 if proxy:
196 proxy = prepend_scheme_if_needed(proxy, urlparse(url).scheme)
197 conn = ProxyManager(self.poolmanager.connection_from_url(proxy))
198 else:
199 conn = self.poolmanager.connection_from_url(url)
200
201 return conn
202
203 def close(self):
204 """Disposes of any internal state.
205
206 Currently, this just closes the PoolManager, which closes pooled
207 connections.
208 """
209 self.poolmanager.clear()
210
211 def request_url(self, request, proxies):
212 """Obtain the url to use when making the final request.
213
214 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.
216
217 This shoudl not be called from user code, and is only exposed for use
218 when subclassing the
219 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
220
221 :param request: The :class:`PreparedRequest <PreparedRequest>` being sen t.
222 :param proxies: A dictionary of schemes to proxy URLs.
223 """
224 proxies = proxies or {}
225 proxy = proxies.get(urlparse(request.url).scheme)
226
227 if proxy:
228 url, _ = urldefrag(request.url)
229 else:
230 url = request.path_url
231
232 return url
233
234 def add_headers(self, request, **kwargs):
235 """Add any headers needed by the connection. Currently this adds a
236 Proxy-Authorization header.
237
238 This should not be called from user code, and is only exposed for use
239 when subclassing the
240 :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
241
242 :param request: The :class:`PreparedRequest <PreparedRequest>` to add he aders to.
243 :param kwargs: The keyword arguments from the call to send().
244 """
245 proxies = kwargs.get('proxies', {})
246
247 if proxies is None:
248 proxies = {}
249
250 proxy = proxies.get(urlparse(request.url).scheme)
251 username, password = get_auth_from_url(proxy)
252
253 if username and password:
254 # Proxy auth usernames and passwords will be urlencoded, we need
255 # to decode them.
256 username = unquote(username)
257 password = unquote(password)
258 request.headers['Proxy-Authorization'] = _basic_auth_str(username,
259 password)
260
261 def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
262 """Sends PreparedRequest object. Returns Response object.
263
264 :param request: The :class:`PreparedRequest <PreparedRequest>` being sen t.
265 :param stream: (optional) Whether to stream the request content.
266 :param timeout: (optional) The timeout on the request.
267 :param verify: (optional) Whether to verify SSL certificates.
268 :param vert: (optional) Any user-provided SSL certificate to be trusted.
269 :param proxies: (optional) The proxies dictionary to apply to the reques t.
270 """
271
272 conn = self.get_connection(request.url, proxies)
273
274 self.cert_verify(conn, request.url, verify, cert)
275 url = self.request_url(request, proxies)
276 self.add_headers(request, proxies=proxies)
277
278 chunked = not (request.body is None or 'Content-Length' in request.heade rs)
279
280 try:
281 if not chunked:
282 resp = conn.urlopen(
283 method=request.method,
284 url=url,
285 body=request.body,
286 headers=request.headers,
287 redirect=False,
288 assert_same_host=False,
289 preload_content=False,
290 decode_content=False,
291 retries=self.max_retries,
292 timeout=timeout
293 )
294
295 # Send the request.
296 else:
297 if hasattr(conn, 'proxy_pool'):
298 conn = conn.proxy_pool
299
300 low_conn = conn._get_conn(timeout=timeout)
301 low_conn.putrequest(request.method, url, skip_accept_encoding=Tr ue)
302
303 for header, value in request.headers.items():
304 low_conn.putheader(header, value)
305
306 low_conn.endheaders()
307
308 for i in request.body:
309 low_conn.send(hex(len(i))[2:].encode('utf-8'))
310 low_conn.send(b'\r\n')
311 low_conn.send(i)
312 low_conn.send(b'\r\n')
313 low_conn.send(b'0\r\n\r\n')
314
315 r = low_conn.getresponse()
316 resp = HTTPResponse.from_httplib(r,
317 pool=conn,
318 connection=low_conn,
319 preload_content=False,
320 decode_content=False
321 )
322
323 except socket.error as sockerr:
324 raise ConnectionError(sockerr)
325
326 except MaxRetryError as e:
327 raise ConnectionError(e)
328
329 except (_SSLError, _HTTPError) as e:
330 if isinstance(e, _SSLError):
331 raise SSLError(e)
332 elif isinstance(e, TimeoutError):
333 raise Timeout(e)
334 else:
335 raise
336
337 r = self.build_response(request, resp)
338
339 if not stream:
340 r.content
341
342 return r
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698