import socket from collections import namedtuple from unittest import TestCase from unittest.mock import Mock, patch from urllib.request import _parse_proxy from seleniumwire.proxy import socks from seleniumwire.proxy.proxy2 import (ProxyAwareHTTPConnection, ProxyAwareHTTPSConnection, _create_auth_header) class ProxyAwareHTTPConnectionTest(TestCase): def setUp(self): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'http': conf(*_parse_proxy('http://username:password@host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } def test_use_proxy(self): conn = ProxyAwareHTTPConnection(self.config, 'example.com') self.assertTrue(conn.use_proxy) self.assertEqual(conn.host, 'host') def test_is_not_proxied_when_no_proxy(self): self.config['no_proxy'] += ',example.com' conn = ProxyAwareHTTPConnection(self.config, 'example.com') self.assertFalse(conn.use_proxy) self.assertEqual(conn.host, 'example.com') def test_is_not_proxied_when_no_config(self): self.config = {} conn = ProxyAwareHTTPConnection(self.config, 'example.com') self.assertFalse(conn.use_proxy) self.assertEqual(conn.host, 'example.com') @patch('seleniumwire.proxy.proxy2.HTTPConnection.request') def test_request_uses_absolute_url(self, mock_request): conn = ProxyAwareHTTPConnection(self.config, 'example.com') conn._create_connection = Mock() conn.request('GET', '/foobar') mock_request.assert_called_once_with( 'GET', 'http://example.com/foobar', None, headers={'Proxy-Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='} ) @patch('seleniumwire.proxy.proxy2.HTTPConnection.request') def test_request_uses_original_url_when_not_proxied(self, mock_request): self.config = {} conn = ProxyAwareHTTPConnection(self.config, 'example.com') conn._create_connection = Mock() conn.request('GET', '/foobar') mock_request.assert_called_once_with( 'GET', '/foobar', None, headers={} ) @patch('seleniumwire.proxy.proxy2.socks') def test_connect_does_not_use_socks_proxy(self, mock_socks): conn = ProxyAwareHTTPConnection(self.config, 'example.com') conn._create_connection = Mock() conn.connect() assert mock_socks._create_connection.call_count == 0 @patch('seleniumwire.proxy.proxy2.socks') def test_connect_uses_socks5_proxy(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'http': conf(*_parse_proxy('socks5://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } mock_socks.PROXY_TYPE_SOCKS5 = socks.PROXY_TYPE_SOCKS5 conn = ProxyAwareHTTPConnection(self.config, 'example.com') conn.connect() mock_socks.create_connection.assert_called_once_with( ('example.com', 80), socket._GLOBAL_DEFAULT_TIMEOUT, None, socks.PROXY_TYPE_SOCKS5, 'socks_host', 3128, False, 'socks_user', 'socks_pass', ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) ) @patch('seleniumwire.proxy.proxy2.socks') def test_connect_uses_remote_dns(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'http': conf(*_parse_proxy('socks5h://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } mock_socks.PROXY_TYPE_SOCKS5 = socks.PROXY_TYPE_SOCKS5 conn = ProxyAwareHTTPConnection(self.config, 'example.com') conn.connect() mock_socks.create_connection.assert_called_once_with( ('example.com', 80), socket._GLOBAL_DEFAULT_TIMEOUT, None, socks.PROXY_TYPE_SOCKS5, 'socks_host', 3128, True, 'socks_user', 'socks_pass', ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) ) @patch('seleniumwire.proxy.proxy2.socks') def test_connect_uses_socks4_proxy(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'http': conf(*_parse_proxy('socks4://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } mock_socks.PROXY_TYPE_SOCKS4 = socks.PROXY_TYPE_SOCKS4 conn = ProxyAwareHTTPConnection(self.config, 'example.com') conn.connect() mock_socks.create_connection.assert_called_once_with( ('example.com', 80), socket._GLOBAL_DEFAULT_TIMEOUT, None, socks.PROXY_TYPE_SOCKS4, 'socks_host', 3128, False, 'socks_user', 'socks_pass', ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) ) @patch('seleniumwire.proxy.proxy2.socks') def test_raises_exception_when_invalid_socks_scheme(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'http': conf(*_parse_proxy('socks6://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } conn = ProxyAwareHTTPConnection(self.config, 'example.com') with self.assertRaises(TypeError): conn.connect() class ProxyAwareHTTPSConnectionTest(TestCase): def setUp(self): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'https': conf(*_parse_proxy('https://username:password@host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } def test_use_proxy(self): conn = ProxyAwareHTTPSConnection(self.config, 'example.com') self.assertTrue(conn.use_proxy) self.assertEqual(conn.host, 'host') @patch('seleniumwire.proxy.proxy2.HTTPSConnection.set_tunnel') def test_set_tunnel_is_called(self, mock_set_tunnel): ProxyAwareHTTPSConnection(self.config, 'example.com') mock_set_tunnel.assert_called_once_with( 'example.com', headers={'Proxy-Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='} ) def test_is_not_proxied_when_no_proxy(self): self.config['no_proxy'] += ',example.com' conn = ProxyAwareHTTPSConnection(self.config, 'example.com') self.assertFalse(conn.use_proxy) self.assertEqual(conn.host, 'example.com') def test_is_not_proxied_when_no_config(self): self.config = {} conn = ProxyAwareHTTPSConnection(self.config, 'example.com') self.assertFalse(conn.use_proxy) self.assertEqual(conn.host, 'example.com') @patch('seleniumwire.proxy.proxy2.HTTPSConnection.set_tunnel') def test_set_tunnel_is_not_called(self, mock_set_tunnel): self.config = {} ProxyAwareHTTPSConnection(self.config, 'example.com') self.assertEqual(mock_set_tunnel.call_count, 0) @patch('seleniumwire.proxy.proxy2.HTTPSConnection.set_tunnel') def test_set_tunnel_is_not_called_when_socks(self, mock_set_tunnel): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'https': conf(*_parse_proxy('socks5://username:password@host:3128')) } ProxyAwareHTTPSConnection(self.config, 'example.com') self.assertEqual(mock_set_tunnel.call_count, 0) @patch('seleniumwire.proxy.proxy2.socks') @patch('seleniumwire.proxy.proxy2.HTTPSConnection.connect') @patch('seleniumwire.proxy.proxy2.HTTPSConnection.set_tunnel') def test_connect_does_not_use_socks_proxy(self, mock_set_tunnel, mock_connect, mock_socks): conn = ProxyAwareHTTPSConnection(self.config, 'example.com') conn.connect() assert mock_socks._create_connection.call_count == 0 mock_connect.assert_called_once_with() @patch('seleniumwire.proxy.proxy2.socks') def test_connect_uses_socks5_proxy(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'https': conf(*_parse_proxy('socks5://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } mock_socks.PROXY_TYPE_SOCKS5 = socks.PROXY_TYPE_SOCKS5 conn = ProxyAwareHTTPSConnection(self.config, 'example.com', context=Mock()) conn.connect() mock_socks.create_connection.assert_called_once_with( ('example.com', 443), socket._GLOBAL_DEFAULT_TIMEOUT, None, socks.PROXY_TYPE_SOCKS5, 'socks_host', 3128, False, 'socks_user', 'socks_pass', ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) ) @patch('seleniumwire.proxy.proxy2.socks') def test_connect_uses_remote_dns(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'https': conf(*_parse_proxy('socks5h://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } mock_socks.PROXY_TYPE_SOCKS5 = socks.PROXY_TYPE_SOCKS5 conn = ProxyAwareHTTPSConnection(self.config, 'example.com', context=Mock()) conn.connect() mock_socks.create_connection.assert_called_once_with( ('example.com', 443), socket._GLOBAL_DEFAULT_TIMEOUT, None, socks.PROXY_TYPE_SOCKS5, 'socks_host', 3128, True, 'socks_user', 'socks_pass', ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) ) @patch('seleniumwire.proxy.proxy2.socks') def test_connect_uses_socks4_proxy(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'https': conf(*_parse_proxy('socks4://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } mock_socks.PROXY_TYPE_SOCKS4 = socks.PROXY_TYPE_SOCKS4 conn = ProxyAwareHTTPSConnection(self.config, 'example.com', context=Mock()) conn.connect() mock_socks.create_connection.assert_called_once_with( ('example.com', 443), socket._GLOBAL_DEFAULT_TIMEOUT, None, socks.PROXY_TYPE_SOCKS4, 'socks_host', 3128, False, 'socks_user', 'socks_pass', ((socket.IPPROTO_TCP, socket.TCP_NODELAY, 1),) ) @patch('seleniumwire.proxy.proxy2.socks') def test_raises_exception_when_invalid_socks_scheme(self, mock_socks): conf = namedtuple('ProxyConf', 'scheme username password hostport') self.config = { 'https': conf(*_parse_proxy('socks6://socks_user:socks_pass@socks_host:3128')), 'no_proxy': 'localhost,127.0.0.1,dev_server:8080' } conn = ProxyAwareHTTPSConnection(self.config, 'example.com', context=Mock()) with self.assertRaises(TypeError): conn.connect() class ProxyAuthHeaderTest(TestCase): def test_create_header(self): username = 'username' password = 'password' custom_proxy_authorization = None headers = _create_auth_header(username, password, custom_proxy_authorization) self.assertEqual(headers, {'Proxy-Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}) def test_create_header_missing_username(self): username = None password = 'password' custom_proxy_authorization = None headers = _create_auth_header(username, password, custom_proxy_authorization) self.assertEqual(headers, {}) def test_create_header_missing_password(self): username = 'username' password = None custom_proxy_authorization = None headers = _create_auth_header(username, password, custom_proxy_authorization) self.assertEqual(headers, {}) def test_create_header_custom_proxy_authorization(self): username = None password = None custom_proxy_authorization = 'Basic dXNlcm5hbWU6cGFzc3dvcmQ=' headers = _create_auth_header(username, password, custom_proxy_authorization) self.assertEqual(headers, {'Proxy-Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}) def test_create_header_quoted(self): username = 'username%3b' password = 'password%3b' custom_proxy_authorization = None headers = _create_auth_header(username, password, custom_proxy_authorization) self.assertEqual(headers, {'Proxy-Authorization': 'Basic dXNlcm5hbWU7OnBhc3N3b3JkOw=='})