Allow SOCKSConnection to parse username and password from URL
MODIFY
CHANGES.rst
CHANGES.rst
@@ -24,6 +24,8 @@ dev (master)
* ``read_chunked()`` on a closed response returns no chunks. (Issue #1088)
+* Added support for auth info in url for SOCKS proxy (Pull #1363)
+
* ... [Short description of non-trivial change.] (Issue #)

MODIFY
CONTRIBUTORS.txt
CONTRIBUTORS.txt
@@ -249,5 +249,8 @@ In chronological order:
* Dominique Leuenberger <dimstar@opensuse.org>
* Minor fixes in the test suite
+* Aleksei Alekseev <alekseev.yeskela@gmail.com>
+ * using auth info for socks proxy
+
* [Your name or handle] <[email or website]>
* [Brief summary of your changes]

MODIFY
test/contrib/test_socks.py
test/contrib/test_socks.py
@@ -398,6 +398,45 @@ class TestSocks5Proxy(IPV4SocketDummyServerTestCase):
self.assertEqual(response.data, b'')
self.assertEqual(response.headers['Server'], 'SocksTestServer')
+ def test_socks_with_auth_in_url(self):
+ """
+ Test when we have auth info in url, i.e.
+ socks5://user:pass@host:port and no username/password as params
+ """
+ def request_handler(listener):
+ sock = listener.accept()[0]
+
+ handler = handle_socks5_negotiation(
+ sock, negotiate=True, username=b'user', password=b'pass'
+ )
+ addr, port = next(handler)
+
+ self.assertEqual(addr, '16.17.18.19')
+ self.assertEqual(port, 80)
+ handler.send(True)
+
+ while True:
+ buf = sock.recv(65535)
+ if buf.endswith(b'\r\n\r\n'):
+ break
+
+ sock.sendall(b'HTTP/1.1 200 OK\r\n'
+ b'Server: SocksTestServer\r\n'
+ b'Content-Length: 0\r\n'
+ b'\r\n')
+ sock.close()
+
+ self._start_server(request_handler)
+ proxy_url = "socks5://user:pass@%s:%s" % (self.host, self.port)
+ pm = socks.SOCKSProxyManager(proxy_url)
+ self.addCleanup(pm.clear)
+
+ response = pm.request('GET', 'http://16.17.18.19')
+
+ self.assertEqual(response.status, 200)
+ self.assertEqual(response.data, b'')
+ self.assertEqual(response.headers['Server'], 'SocksTestServer')
+
def test_socks_with_invalid_password(self):
def request_handler(listener):
sock = listener.accept()[0]

MODIFY
urllib3/contrib/socks.py
urllib3/contrib/socks.py
@@ -152,6 +152,10 @@ class SOCKSProxyManager(PoolManager):
num_pools=10, headers=None, **connection_pool_kw):
parsed = parse_url(proxy_url)
+ if username is None and password is None and parsed.auth is not None:
+ split = parsed.auth.split(':')
+ if len(split) == 2:
+ username, password = split
if parsed.scheme == 'socks5':
socks_version = socks.PROXY_TYPE_SOCKS5
rdns = False

Allow SOCKSConnection to parse username and password from URL (#1363)