comparison planemo/lib/python3.7/site-packages/urllib3/contrib/socks.py @ 1:56ad4e20f292 draft

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