Index: third_party/google-endpoints/urllib3/contrib/socks.py |
diff --git a/third_party/google-endpoints/urllib3/contrib/socks.py b/third_party/google-endpoints/urllib3/contrib/socks.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..39e92fde19b1332a7c90f6b6afe2a69601e9a66d |
--- /dev/null |
+++ b/third_party/google-endpoints/urllib3/contrib/socks.py |
@@ -0,0 +1,188 @@ |
+# -*- coding: utf-8 -*- |
+""" |
+This module contains provisional support for SOCKS proxies from within |
+urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) and |
+SOCKS5. To enable its functionality, either install PySocks or install this |
+module with the ``socks`` extra. |
+ |
+The SOCKS implementation supports the full range of urllib3 features. It also |
+supports the following SOCKS features: |
+ |
+- SOCKS4 |
+- SOCKS4a |
+- SOCKS5 |
+- Usernames and passwords for the SOCKS proxy |
+ |
+Known Limitations: |
+ |
+- Currently PySocks does not support contacting remote websites via literal |
+ IPv6 addresses. Any such connection attempt will fail. You must use a domain |
+ name. |
+- Currently PySocks does not support IPv6 connections to the SOCKS proxy. Any |
+ such connection attempt will fail. |
+""" |
+from __future__ import absolute_import |
+ |
+try: |
+ import socks |
+except ImportError: |
+ import warnings |
+ from ..exceptions import DependencyWarning |
+ |
+ warnings.warn(( |
+ 'SOCKS support in urllib3 requires the installation of optional ' |
+ 'dependencies: specifically, PySocks. For more information, see ' |
+ 'https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies' |
+ ), |
+ DependencyWarning |
+ ) |
+ raise |
+ |
+from socket import error as SocketError, timeout as SocketTimeout |
+ |
+from ..connection import ( |
+ HTTPConnection, HTTPSConnection |
+) |
+from ..connectionpool import ( |
+ HTTPConnectionPool, HTTPSConnectionPool |
+) |
+from ..exceptions import ConnectTimeoutError, NewConnectionError |
+from ..poolmanager import PoolManager |
+from ..util.url import parse_url |
+ |
+try: |
+ import ssl |
+except ImportError: |
+ ssl = None |
+ |
+ |
+class SOCKSConnection(HTTPConnection): |
+ """ |
+ A plain-text HTTP connection that connects via a SOCKS proxy. |
+ """ |
+ def __init__(self, *args, **kwargs): |
+ self._socks_options = kwargs.pop('_socks_options') |
+ super(SOCKSConnection, self).__init__(*args, **kwargs) |
+ |
+ def _new_conn(self): |
+ """ |
+ Establish a new connection via the SOCKS proxy. |
+ """ |
+ extra_kw = {} |
+ if self.source_address: |
+ extra_kw['source_address'] = self.source_address |
+ |
+ if self.socket_options: |
+ extra_kw['socket_options'] = self.socket_options |
+ |
+ try: |
+ conn = socks.create_connection( |
+ (self.host, self.port), |
+ proxy_type=self._socks_options['socks_version'], |
+ proxy_addr=self._socks_options['proxy_host'], |
+ proxy_port=self._socks_options['proxy_port'], |
+ proxy_username=self._socks_options['username'], |
+ proxy_password=self._socks_options['password'], |
+ proxy_rdns=self._socks_options['rdns'], |
+ timeout=self.timeout, |
+ **extra_kw |
+ ) |
+ |
+ except SocketTimeout as e: |
+ raise ConnectTimeoutError( |
+ self, "Connection to %s timed out. (connect timeout=%s)" % |
+ (self.host, self.timeout)) |
+ |
+ except socks.ProxyError as e: |
+ # This is fragile as hell, but it seems to be the only way to raise |
+ # useful errors here. |
+ if e.socket_err: |
+ error = e.socket_err |
+ if isinstance(error, SocketTimeout): |
+ raise ConnectTimeoutError( |
+ self, |
+ "Connection to %s timed out. (connect timeout=%s)" % |
+ (self.host, self.timeout) |
+ ) |
+ else: |
+ raise NewConnectionError( |
+ self, |
+ "Failed to establish a new connection: %s" % error |
+ ) |
+ else: |
+ raise NewConnectionError( |
+ self, |
+ "Failed to establish a new connection: %s" % e |
+ ) |
+ |
+ except SocketError as e: # Defensive: PySocks should catch all these. |
+ raise NewConnectionError( |
+ self, "Failed to establish a new connection: %s" % e) |
+ |
+ return conn |
+ |
+ |
+# We don't need to duplicate the Verified/Unverified distinction from |
+# urllib3/connection.py here because the HTTPSConnection will already have been |
+# correctly set to either the Verified or Unverified form by that module. This |
+# means the SOCKSHTTPSConnection will automatically be the correct type. |
+class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): |
+ pass |
+ |
+ |
+class SOCKSHTTPConnectionPool(HTTPConnectionPool): |
+ ConnectionCls = SOCKSConnection |
+ |
+ |
+class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): |
+ ConnectionCls = SOCKSHTTPSConnection |
+ |
+ |
+class SOCKSProxyManager(PoolManager): |
+ """ |
+ A version of the urllib3 ProxyManager that routes connections via the |
+ defined SOCKS proxy. |
+ """ |
+ pool_classes_by_scheme = { |
+ 'http': SOCKSHTTPConnectionPool, |
+ 'https': SOCKSHTTPSConnectionPool, |
+ } |
+ |
+ def __init__(self, proxy_url, username=None, password=None, |
+ num_pools=10, headers=None, **connection_pool_kw): |
+ parsed = parse_url(proxy_url) |
+ |
+ if parsed.scheme == 'socks5': |
+ socks_version = socks.PROXY_TYPE_SOCKS5 |
+ rdns = False |
+ elif parsed.scheme == 'socks5h': |
+ socks_version = socks.PROXY_TYPE_SOCKS5 |
+ rdns = True |
+ elif parsed.scheme == 'socks4': |
+ socks_version = socks.PROXY_TYPE_SOCKS4 |
+ rdns = False |
+ elif parsed.scheme == 'socks4a': |
+ socks_version = socks.PROXY_TYPE_SOCKS4 |
+ rdns = True |
+ else: |
+ raise ValueError( |
+ "Unable to determine SOCKS version from %s" % proxy_url |
+ ) |
+ |
+ self.proxy_url = proxy_url |
+ |
+ socks_options = { |
+ 'socks_version': socks_version, |
+ 'proxy_host': parsed.host, |
+ 'proxy_port': parsed.port, |
+ 'username': username, |
+ 'password': password, |
+ 'rdns': rdns |
+ } |
+ connection_pool_kw['_socks_options'] = socks_options |
+ |
+ super(SOCKSProxyManager, self).__init__( |
+ num_pools, headers, **connection_pool_kw |
+ ) |
+ |
+ self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme |