PageRenderTime 59ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/plugin.video.glarab/resources/urllib3/connectionpool.py

https://github.com/ntahri/repository.arabic.xbmc-addons
Python | 521 lines | 467 code | 32 blank | 22 comment | 11 complexity | 22b53cebe948d5fe63a8cbf3ea95ce96 MD5 | raw file
Possible License(s): AGPL-1.0
  1. # urllib3/connectionpool.py
  2. # Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
  3. #
  4. # This module is part of urllib3 and is released under
  5. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  6. import logging
  7. import socket
  8. from socket import error as SocketError, timeout as SocketTimeout
  9. try: # Python 3
  10. from http.client import HTTPConnection, HTTPException
  11. from http.client import HTTP_PORT, HTTPS_PORT
  12. except ImportError:
  13. from httplib import HTTPConnection, HTTPException
  14. from httplib import HTTP_PORT, HTTPS_PORT
  15. try: # Python 3
  16. from queue import LifoQueue, Empty, Full
  17. except ImportError:
  18. from Queue import LifoQueue, Empty, Full
  19. try: # Compiled with SSL?
  20. HTTPSConnection = object
  21. BaseSSLError = None
  22. ssl = None
  23. try: # Python 3
  24. from http.client import HTTPSConnection
  25. except ImportError:
  26. from httplib import HTTPSConnection
  27. import ssl
  28. BaseSSLError = ssl.SSLError
  29. except (ImportError, AttributeError):
  30. pass
  31. from .request import RequestMethods
  32. from .response import HTTPResponse
  33. from .util import get_host, is_connection_dropped
  34. from .exceptions import (
  35. EmptyPoolError,
  36. HostChangedError,
  37. MaxRetryError,
  38. SSLError,
  39. TimeoutError,
  40. )
  41. from .packages.ssl_match_hostname import match_hostname, CertificateError
  42. from .packages import six
  43. xrange = six.moves.xrange
  44. log = logging.getLogger(__name__)
  45. _Default = object()
  46. port_by_scheme = {
  47. 'http': HTTP_PORT,
  48. 'https': HTTPS_PORT,
  49. }
  50. ## Connection objects (extension of httplib)
  51. class VerifiedHTTPSConnection(HTTPSConnection):
  52. """
  53. Based on httplib.HTTPSConnection but wraps the socket with
  54. SSL certification.
  55. """
  56. cert_reqs = None
  57. ca_certs = None
  58. def set_cert(self, key_file=None, cert_file=None,
  59. cert_reqs='CERT_NONE', ca_certs=None):
  60. ssl_req_scheme = {
  61. 'CERT_NONE': ssl.CERT_NONE,
  62. 'CERT_OPTIONAL': ssl.CERT_OPTIONAL,
  63. 'CERT_REQUIRED': ssl.CERT_REQUIRED
  64. }
  65. self.key_file = key_file
  66. self.cert_file = cert_file
  67. self.cert_reqs = ssl_req_scheme.get(cert_reqs) or ssl.CERT_NONE
  68. self.ca_certs = ca_certs
  69. def connect(self):
  70. # Add certificate verification
  71. sock = socket.create_connection((self.host, self.port), self.timeout)
  72. # Wrap socket using verification with the root certs in
  73. # trusted_root_certs
  74. self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
  75. cert_reqs=self.cert_reqs,
  76. ca_certs=self.ca_certs)
  77. if self.ca_certs:
  78. match_hostname(self.sock.getpeercert(), self.host)
  79. ## Pool objects
  80. class ConnectionPool(object):
  81. """
  82. Base class for all connection pools, such as
  83. :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
  84. """
  85. scheme = None
  86. QueueCls = LifoQueue
  87. def __init__(self, host, port=None):
  88. self.host = host
  89. self.port = port
  90. def __str__(self):
  91. return '%s(host=%r, port=%r)' % (type(self).__name__,
  92. self.host, self.port)
  93. class HTTPConnectionPool(ConnectionPool, RequestMethods):
  94. """
  95. Thread-safe connection pool for one host.
  96. :param host:
  97. Host used for this HTTP Connection (e.g. "localhost"), passed into
  98. :class:`httplib.HTTPConnection`.
  99. :param port:
  100. Port used for this HTTP Connection (None is equivalent to 80), passed
  101. into :class:`httplib.HTTPConnection`.
  102. :param strict:
  103. Causes BadStatusLine to be raised if the status line can't be parsed
  104. as a valid HTTP/1.0 or 1.1 status line, passed into
  105. :class:`httplib.HTTPConnection`.
  106. :param timeout:
  107. Socket timeout for each individual connection, can be a float. None
  108. disables timeout.
  109. :param maxsize:
  110. Number of connections to save that can be reused. More than 1 is useful
  111. in multithreaded situations. If ``block`` is set to false, more
  112. connections will be created but they will not be saved once they've
  113. been used.
  114. :param block:
  115. If set to True, no more than ``maxsize`` connections will be used at
  116. a time. When no free connections are available, the call will block
  117. until a connection has been released. This is a useful side effect for
  118. particular multithreaded situations where one does not want to use more
  119. than maxsize connections per host to prevent flooding.
  120. :param headers:
  121. Headers to include with all requests, unless other headers are given
  122. explicitly.
  123. """
  124. scheme = 'http'
  125. def __init__(self, host, port=None, strict=False, timeout=None, maxsize=1,
  126. block=False, headers=None):
  127. super(HTTPConnectionPool, self).__init__(host, port)
  128. self.strict = strict
  129. self.timeout = timeout
  130. self.pool = self.QueueCls(maxsize)
  131. self.block = block
  132. self.headers = headers or {}
  133. # Fill the queue up so that doing get() on it will block properly
  134. for _ in xrange(maxsize):
  135. self.pool.put(None)
  136. # These are mostly for testing and debugging purposes.
  137. self.num_connections = 0
  138. self.num_requests = 0
  139. def _new_conn(self):
  140. """
  141. Return a fresh :class:`httplib.HTTPConnection`.
  142. """
  143. self.num_connections += 1
  144. log.info("Starting new HTTP connection (%d): %s" %
  145. (self.num_connections, self.host))
  146. return HTTPConnection(host=self.host, port=self.port)
  147. def _get_conn(self, timeout=None):
  148. """
  149. Get a connection. Will return a pooled connection if one is available.
  150. If no connections are available and :prop:`.block` is ``False``, then a
  151. fresh connection is returned.
  152. :param timeout:
  153. Seconds to wait before giving up and raising
  154. :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and
  155. :prop:`.block` is ``True``.
  156. """
  157. conn = None
  158. try:
  159. conn = self.pool.get(block=self.block, timeout=timeout)
  160. # If this is a persistent connection, check if it got disconnected
  161. if conn and is_connection_dropped(conn):
  162. log.info("Resetting dropped connection: %s" % self.host)
  163. conn.close()
  164. except Empty:
  165. if self.block:
  166. raise EmptyPoolError(self,
  167. "Pool reached maximum size and no more "
  168. "connections are allowed.")
  169. pass # Oh well, we'll create a new connection then
  170. return conn or self._new_conn()
  171. def _put_conn(self, conn):
  172. """
  173. Put a connection back into the pool.
  174. :param conn:
  175. Connection object for the current host and port as returned by
  176. :meth:`._new_conn` or :meth:`._get_conn`.
  177. If the pool is already full, the connection is discarded because we
  178. exceeded maxsize. If connections are discarded frequently, then maxsize
  179. should be increased.
  180. """
  181. try:
  182. self.pool.put(conn, block=False)
  183. except Full:
  184. # This should never happen if self.block == True
  185. log.warning("HttpConnectionPool is full, discarding connection: %s"
  186. % self.host)
  187. def _make_request(self, conn, method, url, timeout=_Default,
  188. **httplib_request_kw):
  189. """
  190. Perform a request on a given httplib connection object taken from our
  191. pool.
  192. """
  193. self.num_requests += 1
  194. if timeout is _Default:
  195. timeout = self.timeout
  196. conn.timeout = timeout # This only does anything in Py26+
  197. conn.request(method, url, **httplib_request_kw)
  198. # Set timeout
  199. sock = getattr(conn, 'sock', False) # AppEngine doesn't have sock attr.
  200. if sock:
  201. sock.settimeout(timeout)
  202. httplib_response = conn.getresponse()
  203. log.debug("\"%s %s %s\" %s %s" %
  204. (method, url,
  205. conn._http_vsn_str, # pylint: disable-msg=W0212
  206. httplib_response.status, httplib_response.length))
  207. return httplib_response
  208. def is_same_host(self, url):
  209. """
  210. Check if the given ``url`` is a member of the same host as this
  211. connection pool.
  212. """
  213. # TODO: Add optional support for socket.gethostbyname checking.
  214. scheme, host, port = get_host(url)
  215. if self.port and not port:
  216. # Use explicit default port for comparison when none is given.
  217. port = port_by_scheme.get(scheme)
  218. return (url.startswith('/') or
  219. (scheme, host, port) == (self.scheme, self.host, self.port))
  220. def urlopen(self, method, url, body=None, headers=None, retries=3,
  221. redirect=True, assert_same_host=True, timeout=_Default,
  222. pool_timeout=None, release_conn=None, **response_kw):
  223. """
  224. Get a connection from the pool and perform an HTTP request. This is the
  225. lowest level call for making a request, so you'll need to specify all
  226. the raw details.
  227. .. note::
  228. More commonly, it's appropriate to use a convenience method provided
  229. by :class:`.RequestMethods`, such as :meth:`request`.
  230. .. note::
  231. `release_conn` will only behave as expected if
  232. `preload_content=False` because we want to make
  233. `preload_content=False` the default behaviour someday soon without
  234. breaking backwards compatibility.
  235. :param method:
  236. HTTP request method (such as GET, POST, PUT, etc.)
  237. :param body:
  238. Data to send in the request body (useful for creating
  239. POST requests, see HTTPConnectionPool.post_url for
  240. more convenience).
  241. :param headers:
  242. Dictionary of custom headers to send, such as User-Agent,
  243. If-None-Match, etc. If None, pool headers are used. If provided,
  244. these headers completely replace any pool-specific headers.
  245. :param retries:
  246. Number of retries to allow before raising a MaxRetryError exception.
  247. :param redirect:
  248. Automatically handle redirects (status codes 301, 302, 303, 307),
  249. each redirect counts as a retry.
  250. :param assert_same_host:
  251. If ``True``, will make sure that the host of the pool requests is
  252. consistent else will raise HostChangedError. When False, you can
  253. use the pool on an HTTP proxy and request foreign hosts.
  254. :param timeout:
  255. If specified, overrides the default timeout for this one request.
  256. :param pool_timeout:
  257. If set and the pool is set to block=True, then this method will
  258. block for ``pool_timeout`` seconds and raise EmptyPoolError if no
  259. connection is available within the time period.
  260. :param release_conn:
  261. If False, then the urlopen call will not release the connection
  262. back into the pool once a response is received (but will release if
  263. you read the entire contents of the response such as when
  264. `preload_content=True`). This is useful if you're not preloading
  265. the response's content immediately. You will need to call
  266. ``r.release_conn()`` on the response ``r`` to return the connection
  267. back into the pool. If None, it takes the value of
  268. ``response_kw.get('preload_content', True)``.
  269. :param \**response_kw:
  270. Additional parameters are passed to
  271. :meth:`urllib3.response.HTTPResponse.from_httplib`
  272. """
  273. if headers is None:
  274. headers = self.headers
  275. if retries < 0:
  276. raise MaxRetryError(self, url)
  277. if timeout is _Default:
  278. timeout = self.timeout
  279. if release_conn is None:
  280. release_conn = response_kw.get('preload_content', True)
  281. # Check host
  282. if assert_same_host and not self.is_same_host(url):
  283. host = "%s://%s" % (self.scheme, self.host)
  284. if self.port:
  285. host = "%s:%d" % (host, self.port)
  286. raise HostChangedError(self, url, retries - 1)
  287. conn = None
  288. try:
  289. # Request a connection from the queue
  290. # (Could raise SocketError: Bad file descriptor)
  291. conn = self._get_conn(timeout=pool_timeout)
  292. # Make the request on the httplib connection object
  293. httplib_response = self._make_request(conn, method, url,
  294. timeout=timeout,
  295. body=body, headers=headers)
  296. # If we're going to release the connection in ``finally:``, then
  297. # the request doesn't need to know about the connection. Otherwise
  298. # it will also try to release it and we'll have a double-release
  299. # mess.
  300. response_conn = not release_conn and conn
  301. # Import httplib's response into our own wrapper object
  302. response = HTTPResponse.from_httplib(httplib_response,
  303. pool=self,
  304. connection=response_conn,
  305. **response_kw)
  306. # else:
  307. # The connection will be put back into the pool when
  308. # ``response.release_conn()`` is called (implicitly by
  309. # ``response.read()``)
  310. except Empty as e:
  311. # Timed out by queue
  312. raise TimeoutError(self, "Request timed out. (pool_timeout=%s)" %
  313. pool_timeout)
  314. except SocketTimeout as e:
  315. # Timed out by socket
  316. raise TimeoutError(self, "Request timed out. (timeout=%s)" %
  317. timeout)
  318. except BaseSSLError as e:
  319. # SSL certificate error
  320. raise SSLError(e)
  321. except CertificateError as e:
  322. # Name mismatch
  323. raise SSLError(e)
  324. except (HTTPException, SocketError) as e:
  325. # Connection broken, discard. It will be replaced next _get_conn().
  326. conn = None
  327. # This is necessary so we can access e below
  328. err = e
  329. finally:
  330. if conn and release_conn:
  331. # Put the connection back to be reused
  332. self._put_conn(conn)
  333. if not conn:
  334. log.warn("Retrying (%d attempts remain) after connection "
  335. "broken by '%r': %s" % (retries, err, url))
  336. return self.urlopen(method, url, body, headers, retries - 1,
  337. redirect, assert_same_host) # Try again
  338. # Handle redirect?
  339. redirect_location = redirect and response.get_redirect_location()
  340. if redirect_location:
  341. log.info("Redirecting %s -> %s" % (url, redirect_location))
  342. return self.urlopen(method, redirect_location, body, headers,
  343. retries - 1, redirect, assert_same_host)
  344. return response
  345. class HTTPSConnectionPool(HTTPConnectionPool):
  346. """
  347. Same as :class:`.HTTPConnectionPool`, but HTTPS.
  348. When Python is compiled with the :mod:`ssl` module, then
  349. :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates,
  350. instead of :class:httplib.HTTPSConnection`.
  351. The ``key_file``, ``cert_file``, ``cert_reqs``, and ``ca_certs`` parameters
  352. are only used if :mod:`ssl` is available and are fed into
  353. :meth:`ssl.wrap_socket` to upgrade the connection socket into an SSL socket.
  354. """
  355. scheme = 'https'
  356. def __init__(self, host, port=None,
  357. strict=False, timeout=None, maxsize=1,
  358. block=False, headers=None,
  359. key_file=None, cert_file=None,
  360. cert_reqs='CERT_NONE', ca_certs=None):
  361. super(HTTPSConnectionPool, self).__init__(host, port,
  362. strict, timeout, maxsize,
  363. block, headers)
  364. self.key_file = key_file
  365. self.cert_file = cert_file
  366. self.cert_reqs = cert_reqs
  367. self.ca_certs = ca_certs
  368. def _new_conn(self):
  369. """
  370. Return a fresh :class:`httplib.HTTPSConnection`.
  371. """
  372. self.num_connections += 1
  373. log.info("Starting new HTTPS connection (%d): %s"
  374. % (self.num_connections, self.host))
  375. if not ssl: # Platform-specific: Python compiled without +ssl
  376. if not HTTPSConnection or HTTPSConnection is object:
  377. raise SSLError("Can't connect to HTTPS URL because the SSL "
  378. "module is not available.")
  379. return HTTPSConnection(host=self.host, port=self.port)
  380. connection = VerifiedHTTPSConnection(host=self.host, port=self.port)
  381. connection.set_cert(key_file=self.key_file, cert_file=self.cert_file,
  382. cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
  383. return connection
  384. def connection_from_url(url, **kw):
  385. """
  386. Given a url, return an :class:`.ConnectionPool` instance of its host.
  387. This is a shortcut for not having to parse out the scheme, host, and port
  388. of the url before creating an :class:`.ConnectionPool` instance.
  389. :param url:
  390. Absolute URL string that must include the scheme. Port is optional.
  391. :param \**kw:
  392. Passes additional parameters to the constructor of the appropriate
  393. :class:`.ConnectionPool`. Useful for specifying things like
  394. timeout, maxsize, headers, etc.
  395. Example: ::
  396. >>> conn = connection_from_url('http://google.com/')
  397. >>> r = conn.request('GET', '/')
  398. """
  399. scheme, host, port = get_host(url)
  400. if scheme == 'https':
  401. return HTTPSConnectionPool(host, port=port, **kw)
  402. else:
  403. return HTTPConnectionPool(host, port=port, **kw)