comparison env/lib/python3.9/site-packages/urllib3/contrib/socks.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 # -*- coding: utf-8 -*-
2 """
3 This module contains provisional support for SOCKS proxies from within
4 urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and
5 SOCKS5. To enable its functionality, either install PySocks or install this
6 module with the ``socks`` extra.
7
8 The SOCKS implementation supports the full range of urllib3 features. It also
9 supports the following SOCKS features:
10
11 - SOCKS4A (``proxy_url='socks4a://...``)
12 - SOCKS4 (``proxy_url='socks4://...``)
13 - SOCKS5 with remote DNS (``proxy_url='socks5h://...``)
14 - SOCKS5 with local DNS (``proxy_url='socks5://...``)
15 - Usernames and passwords for the SOCKS proxy
16
17 .. note::
18 It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in
19 your ``proxy_url`` to ensure that DNS resolution is done from the remote
20 server instead of client-side when connecting to a domain name.
21
22 SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5
23 supports IPv4, IPv6, and domain names.
24
25 When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url``
26 will be sent as the ``userid`` section of the SOCKS request:
27
28 .. code-block:: python
29
30 proxy_url="socks4a://<userid>@proxy-host"
31
32 When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion
33 of the ``proxy_url`` will be sent as the username/password to authenticate
34 with the proxy:
35
36 .. code-block:: python
37
38 proxy_url="socks5h://<username>:<password>@proxy-host"
39
40 """
41 from __future__ import absolute_import
42
43 try:
44 import socks
45 except ImportError:
46 import warnings
47
48 from ..exceptions import DependencyWarning
49
50 warnings.warn(
51 (
52 "SOCKS support in urllib3 requires the installation of optional "
53 "dependencies: specifically, PySocks. For more information, see "
54 "https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies"
55 ),
56 DependencyWarning,
57 )
58 raise
59
60 from socket import error as SocketError
61 from socket import timeout as SocketTimeout
62
63 from ..connection import HTTPConnection, HTTPSConnection
64 from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool
65 from ..exceptions import ConnectTimeoutError, NewConnectionError
66 from ..poolmanager import PoolManager
67 from ..util.url import parse_url
68
69 try:
70 import ssl
71 except ImportError:
72 ssl = None
73
74
75 class SOCKSConnection(HTTPConnection):
76 """
77 A plain-text HTTP connection that connects via a SOCKS proxy.
78 """
79
80 def __init__(self, *args, **kwargs):
81 self._socks_options = kwargs.pop("_socks_options")
82 super(SOCKSConnection, self).__init__(*args, **kwargs)
83
84 def _new_conn(self):
85 """
86 Establish a new connection via the SOCKS proxy.
87 """
88 extra_kw = {}
89 if self.source_address:
90 extra_kw["source_address"] = self.source_address
91
92 if self.socket_options:
93 extra_kw["socket_options"] = self.socket_options
94
95 try:
96 conn = socks.create_connection(
97 (self.host, self.port),
98 proxy_type=self._socks_options["socks_version"],
99 proxy_addr=self._socks_options["proxy_host"],
100 proxy_port=self._socks_options["proxy_port"],
101 proxy_username=self._socks_options["username"],
102 proxy_password=self._socks_options["password"],
103 proxy_rdns=self._socks_options["rdns"],
104 timeout=self.timeout,
105 **extra_kw
106 )
107
108 except SocketTimeout:
109 raise ConnectTimeoutError(
110 self,
111 "Connection to %s timed out. (connect timeout=%s)"
112 % (self.host, self.timeout),
113 )
114
115 except socks.ProxyError as e:
116 # This is fragile as hell, but it seems to be the only way to raise
117 # useful errors here.
118 if e.socket_err:
119 error = e.socket_err
120 if isinstance(error, SocketTimeout):
121 raise ConnectTimeoutError(
122 self,
123 "Connection to %s timed out. (connect timeout=%s)"
124 % (self.host, self.timeout),
125 )
126 else:
127 raise NewConnectionError(
128 self, "Failed to establish a new connection: %s" % error
129 )
130 else:
131 raise NewConnectionError(
132 self, "Failed to establish a new connection: %s" % e
133 )
134
135 except SocketError as e: # Defensive: PySocks should catch all these.
136 raise NewConnectionError(
137 self, "Failed to establish a new connection: %s" % e
138 )
139
140 return conn
141
142
143 # We don't need to duplicate the Verified/Unverified distinction from
144 # urllib3/connection.py here because the HTTPSConnection will already have been
145 # correctly set to either the Verified or Unverified form by that module. This
146 # means the SOCKSHTTPSConnection will automatically be the correct type.
147 class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection):
148 pass
149
150
151 class SOCKSHTTPConnectionPool(HTTPConnectionPool):
152 ConnectionCls = SOCKSConnection
153
154
155 class SOCKSHTTPSConnectionPool(HTTPSConnectionPool):
156 ConnectionCls = SOCKSHTTPSConnection
157
158
159 class SOCKSProxyManager(PoolManager):
160 """
161 A version of the urllib3 ProxyManager that routes connections via the
162 defined SOCKS proxy.
163 """
164
165 pool_classes_by_scheme = {
166 "http": SOCKSHTTPConnectionPool,
167 "https": SOCKSHTTPSConnectionPool,
168 }
169
170 def __init__(
171 self,
172 proxy_url,
173 username=None,
174 password=None,
175 num_pools=10,
176 headers=None,
177 **connection_pool_kw
178 ):
179 parsed = parse_url(proxy_url)
180
181 if username is None and password is None and parsed.auth is not None:
182 split = parsed.auth.split(":")
183 if len(split) == 2:
184 username, password = split
185 if parsed.scheme == "socks5":
186 socks_version = socks.PROXY_TYPE_SOCKS5
187 rdns = False
188 elif parsed.scheme == "socks5h":
189 socks_version = socks.PROXY_TYPE_SOCKS5
190 rdns = True
191 elif parsed.scheme == "socks4":
192 socks_version = socks.PROXY_TYPE_SOCKS4
193 rdns = False
194 elif parsed.scheme == "socks4a":
195 socks_version = socks.PROXY_TYPE_SOCKS4
196 rdns = True
197 else:
198 raise ValueError("Unable to determine SOCKS version from %s" % proxy_url)
199
200 self.proxy_url = proxy_url
201
202 socks_options = {
203 "socks_version": socks_version,
204 "proxy_host": parsed.host,
205 "proxy_port": parsed.port,
206 "username": username,
207 "password": password,
208 "rdns": rdns,
209 }
210 connection_pool_kw["_socks_options"] = socks_options
211
212 super(SOCKSProxyManager, self).__init__(
213 num_pools, headers, **connection_pool_kw
214 )
215
216 self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme