[PY] Use ProxyManager instead of PoolManager in remote_connection (#8297)

* Use ProxyManager instead of PoolManager in remote_connection

Currently urllib3.PoolManager is used in creating remote
connection to the grid. If a proxy is required to connect
to the grid, we have to use urllib3.ProxyManager instead
of urllib3.PoolManager.

The proxy settings will be taken from https_proxy or http_proxy
environment variables based on the remote grid url passed to the
RemoteConnection class. If proxy environment variable is set,
ProxyManager will be used to create the connection. Otherwise
PoolManager will be used.

Fixes #8053

* Renamed the function to fix flake8 errors

Co-authored-by: Vishnuprakash Puthiya Kovilakath <610731+pkvprakash@users.noreply.github.com>
Co-authored-by: David Burns <david.burns@theautomatedtester.co.uk>
Cr-Mirrored-From: https://chromium.googlesource.com/external/github.com/SeleniumHQ/selenium
Cr-Mirrored-Commit: b4ace9e67a43b44b32033e5bb868b1b5aa85ecc1
diff --git a/selenium/webdriver/firefox/webdriver.py b/selenium/webdriver/firefox/webdriver.py
index d1757d7..2606411 100644
--- a/selenium/webdriver/firefox/webdriver.py
+++ b/selenium/webdriver/firefox/webdriver.py
@@ -36,7 +36,7 @@
 
 
 # Default for log_path variable. To be deleted when deprecations for arguments are removed.
-DEFAULT_LOG_PATH= None
+DEFAULT_LOG_PATH = None
 DEFAULT_EXECUTABLE_PATH = "geckodriver"
 DEFAULT_SERVICE_LOG_PATH = "geckodriver.log"
 
@@ -52,7 +52,7 @@
                  capabilities=None, proxy=None,
                  executable_path=DEFAULT_EXECUTABLE_PATH, options=None,
                  service_log_path=DEFAULT_SERVICE_LOG_PATH,
-                 service_args=None, service=None, desired_capabilities=None, 
+                 service_args=None, service=None, desired_capabilities=None,
                  log_path=DEFAULT_LOG_PATH, keep_alive=True):
         """Starts a new local session of Firefox.
 
@@ -126,7 +126,7 @@
         if service_log_path != DEFAULT_SERVICE_LOG_PATH:
             warnings.warn('service_log_path has been deprecated, please pass in a Service object',
                           DeprecationWarning, stacklevel=2)
-        if service_args != None:
+        if service_args is not None:
             warnings.warn('service_args has been deprecated, please pass in a Service object',
                           DeprecationWarning, stacklevel=2)
 
diff --git a/selenium/webdriver/remote/remote_connection.py b/selenium/webdriver/remote/remote_connection.py
index 31f9ec6..6f1c1b4 100644
--- a/selenium/webdriver/remote/remote_connection.py
+++ b/selenium/webdriver/remote/remote_connection.py
@@ -23,6 +23,7 @@
 
 import certifi
 import urllib3
+import os
 
 try:
     from urllib import parse
@@ -123,6 +124,23 @@
 
         return headers
 
+    def _get_proxy_url(self):
+        if self._url.startswith('https://'):
+            return os.environ.get('https_proxy', os.environ.get('HTTPS_PROXY'))
+        elif self._url.startswith('http://'):
+            return os.environ.get('http_proxy', os.environ.get('HTTP_PROXY'))
+
+    def _get_connection_manager(self):
+        pool_manager_init_args = {
+            'timeout': self._timeout
+        }
+        if self._ca_certs:
+            pool_manager_init_args['cert_reqs'] = 'CERT_REQUIRED'
+            pool_manager_init_args['ca_certs'] = self._ca_certs
+
+        return urllib3.PoolManager(**pool_manager_init_args) if self._proxy_url is None else \
+            urllib3.ProxyManager(self._proxy_url, **pool_manager_init_args)
+
     def __init__(self, remote_server_addr, keep_alive=False, resolve_ip=None):
         if resolve_ip is not None:
             import warnings
@@ -131,14 +149,9 @@
                 DeprecationWarning)
         self.keep_alive = keep_alive
         self._url = remote_server_addr
+        self._proxy_url = self._get_proxy_url()
         if keep_alive:
-            pool_manager_init_args = {
-                'timeout': self._timeout
-            }
-            if self._ca_certs:
-                pool_manager_init_args['cert_reqs'] = 'CERT_REQUIRED'
-                pool_manager_init_args['ca_certs'] = self._ca_certs
-            self._conn = urllib3.PoolManager(**pool_manager_init_args)
+            self._conn = self._get_connection_manager()
 
         self._commands = {
             Command.STATUS: ('GET', '/status'),
@@ -402,13 +415,8 @@
 
             statuscode = resp.status
         else:
-            pool_manager_init_args = {
-                'timeout': self._timeout
-            }
-            if self._ca_certs:
-                pool_manager_init_args['cert_reqs'] = 'CERT_REQUIRED'
-                pool_manager_init_args['ca_certs'] = self._ca_certs
-            with urllib3.PoolManager(**pool_manager_init_args) as http:
+            conn = self._get_connection_manager()
+            with conn as http:
                 resp = http.request(method, url, body=body, headers=headers)
 
             statuscode = resp.status
diff --git a/test/unit/selenium/webdriver/remote/test_remote_connection.py b/test/unit/selenium/webdriver/remote/test_remote_connection.py
index 4441982..18484c9 100644
--- a/test/unit/selenium/webdriver/remote/test_remote_connection.py
+++ b/test/unit/selenium/webdriver/remote/test_remote_connection.py
@@ -16,6 +16,9 @@
 # under the License.
 
 
+import urllib3
+import pytest
+
 try:
     from urllib import parse
 except ImportError:  # above is available in py3+, below is py2.7
@@ -50,6 +53,56 @@
     assert headers.get('Connection') == 'keep-alive'
 
 
+def test_get_proxy_url_http(mock_proxy_settings):
+    proxy = 'http://http_proxy.com:8080'
+    remote_connection = RemoteConnection('http://remote', keep_alive=False)
+    proxy_url = remote_connection._get_proxy_url()
+    assert proxy_url == proxy
+
+
+def test_get_proxy_url_https(mock_proxy_settings):
+    proxy = 'http://https_proxy.com:8080'
+    remote_connection = RemoteConnection('https://remote', keep_alive=False)
+    proxy_url = remote_connection._get_proxy_url()
+    assert proxy_url == proxy
+
+
+def test_get_proxy_url_none(mock_proxy_settings_missing):
+    remote_connection = RemoteConnection('https://remote', keep_alive=False)
+    proxy_url = remote_connection._get_proxy_url()
+    assert proxy_url is None
+
+
+def test_get_connection_manager_without_proxy(mock_proxy_settings_missing):
+    remote_connection = RemoteConnection('http://remote', keep_alive=False)
+    conn = remote_connection._get_connection_manager()
+    assert type(conn) == urllib3.PoolManager
+
+
+def test_get_connection_manager_for_certs_and_timeout():
+    remote_connection = RemoteConnection('http://remote', keep_alive=False)
+    remote_connection.set_timeout(10)
+    conn = remote_connection._get_connection_manager()
+    assert conn.connection_pool_kw['timeout'] == 10
+    assert conn.connection_pool_kw['cert_reqs'] == 'CERT_REQUIRED'
+    assert 'site-packages/certifi/cacert.pem' in conn.connection_pool_kw['ca_certs']
+
+
+def test_get_connection_manager_with_proxy(mock_proxy_settings):
+    remote_connection = RemoteConnection('http://remote', keep_alive=False)
+    conn = remote_connection._get_connection_manager()
+    assert type(conn) == urllib3.ProxyManager
+    assert conn.proxy.scheme == 'http'
+    assert conn.proxy.host == 'http_proxy.com'
+    assert conn.proxy.port == 8080
+    remote_connection_https = RemoteConnection('https://remote', keep_alive=False)
+    conn = remote_connection_https._get_connection_manager()
+    assert type(conn) == urllib3.ProxyManager
+    assert conn.proxy.scheme == 'http'
+    assert conn.proxy.host == 'https_proxy.com'
+    assert conn.proxy.port == 8080
+
+
 class MockResponse:
     code = 200
     headers = []
@@ -62,3 +115,21 @@
 
     def getheader(self, *args, **kwargs):
         pass
+
+
+@pytest.fixture
+def mock_proxy_settings_missing(monkeypatch):
+    monkeypatch.delenv("HTTPS_PROXY", raising=False)
+    monkeypatch.delenv("HTTP_PROXY", raising=False)
+    monkeypatch.delenv("https_proxy", raising=False)
+    monkeypatch.delenv("http_proxy", raising=False)
+
+
+@pytest.fixture
+def mock_proxy_settings(monkeypatch):
+    http_proxy = 'http://http_proxy.com:8080'
+    https_proxy = 'http://https_proxy.com:8080'
+    monkeypatch.setenv("HTTPS_PROXY", https_proxy)
+    monkeypatch.setenv("HTTP_PROXY", http_proxy)
+    monkeypatch.setenv("https_proxy", https_proxy)
+    monkeypatch.setenv("http_proxy", http_proxy)