merge 3.5

Issue #26804: urllib.request will prefer lower_case proxy environment variables
over UPPER_CASE or Mixed_Case ones.

Patch contributed by Hans-Peter Jansen. Reviewed by Martin Panter and Senthil Kumaran.
This commit is contained in:
Senthil Kumaran 2016-04-25 08:18:07 -07:00
commit 0996fa3bd8
5 changed files with 80 additions and 11 deletions

View File

@ -166,6 +166,8 @@ The :mod:`urllib.request` module defines the following functions:
in a case insensitive approach, for all operating systems first, and when it in a case insensitive approach, for all operating systems first, and when it
cannot find it, looks for proxy information from Mac OSX System cannot find it, looks for proxy information from Mac OSX System
Configuration for Mac OS X and Windows Systems Registry for Windows. Configuration for Mac OS X and Windows Systems Registry for Windows.
If both lowercase and uppercase environment variables exist (and disagree),
lowercase is preferred.
The following classes are provided: The following classes are provided:

View File

@ -226,8 +226,46 @@ class ProxyTests(unittest.TestCase):
# getproxies_environment use lowered case truncated (no '_proxy') keys # getproxies_environment use lowered case truncated (no '_proxy') keys
self.assertEqual('localhost', proxies['no']) self.assertEqual('localhost', proxies['no'])
# List of no_proxies with space. # List of no_proxies with space.
self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com') self.env.set('NO_PROXY', 'localhost, anotherdomain.com, newdomain.com:1234')
self.assertTrue(urllib.request.proxy_bypass_environment('anotherdomain.com')) self.assertTrue(urllib.request.proxy_bypass_environment('anotherdomain.com'))
self.assertTrue(urllib.request.proxy_bypass_environment('anotherdomain.com:8888'))
self.assertTrue(urllib.request.proxy_bypass_environment('newdomain.com:1234'))
class ProxyTests_withOrderedEnv(unittest.TestCase):
def setUp(self):
# We need to test conditions, where variable order _is_ significant
self._saved_env = os.environ
# Monkey patch os.environ, start with empty fake environment
os.environ = collections.OrderedDict()
def tearDown(self):
os.environ = self._saved_env
def test_getproxies_environment_prefer_lowercase(self):
# Test lowercase preference with removal
os.environ['no_proxy'] = ''
os.environ['No_Proxy'] = 'localhost'
self.assertFalse(urllib.request.proxy_bypass_environment('localhost'))
self.assertFalse(urllib.request.proxy_bypass_environment('arbitrary'))
os.environ['http_proxy'] = ''
os.environ['HTTP_PROXY'] = 'http://somewhere:3128'
proxies = urllib.request.getproxies_environment()
self.assertEqual({}, proxies)
# Test lowercase preference of proxy bypass and correct matching including ports
os.environ['no_proxy'] = 'localhost, noproxy.com, my.proxy:1234'
os.environ['No_Proxy'] = 'xyz.com'
self.assertTrue(urllib.request.proxy_bypass_environment('localhost'))
self.assertTrue(urllib.request.proxy_bypass_environment('noproxy.com:5678'))
self.assertTrue(urllib.request.proxy_bypass_environment('my.proxy:1234'))
self.assertFalse(urllib.request.proxy_bypass_environment('my.proxy'))
self.assertFalse(urllib.request.proxy_bypass_environment('arbitrary'))
# Test lowercase preference with replacement
os.environ['http_proxy'] = 'http://somewhere:3128'
os.environ['Http_Proxy'] = 'http://somewhereelse:3128'
proxies = urllib.request.getproxies_environment()
self.assertEqual('http://somewhere:3128', proxies['http'])
class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin): class urlopen_HttpTests(unittest.TestCase, FakeHTTPMixin, FakeFTPMixin):
"""Test urlopen() opening a fake http connection.""" """Test urlopen() opening a fake http connection."""

View File

@ -2455,19 +2455,35 @@ def getproxies_environment():
""" """
proxies = {} proxies = {}
# in order to prefer lowercase variables, process environment in
# two passes: first matches any, second pass matches lowercase only
for name, value in os.environ.items(): for name, value in os.environ.items():
name = name.lower() name = name.lower()
if value and name[-6:] == '_proxy': if value and name[-6:] == '_proxy':
proxies[name[:-6]] = value proxies[name[:-6]] = value
for name, value in os.environ.items():
if name[-6:] == '_proxy':
name = name.lower()
if value:
proxies[name[:-6]] = value
else:
proxies.pop(name[:-6], None)
return proxies return proxies
def proxy_bypass_environment(host): def proxy_bypass_environment(host, proxies=None):
"""Test if proxies should not be used for a particular host. """Test if proxies should not be used for a particular host.
Checks the environment for a variable named no_proxy, which should Checks the proxy dict for the value of no_proxy, which should
be a list of DNS suffixes separated by commas, or '*' for all hosts. be a list of comma separated DNS suffixes, or '*' for all hosts.
""" """
no_proxy = os.environ.get('no_proxy', '') or os.environ.get('NO_PROXY', '') if proxies is None:
proxies = getproxies_environment()
# don't bypass, if no_proxy isn't specified
try:
no_proxy = proxies['no']
except KeyError:
return 0
# '*' is special case for always bypass # '*' is special case for always bypass
if no_proxy == '*': if no_proxy == '*':
return 1 return 1
@ -2562,8 +2578,15 @@ if sys.platform == 'darwin':
def proxy_bypass(host): def proxy_bypass(host):
if getproxies_environment(): """Return True, if host should be bypassed.
return proxy_bypass_environment(host)
Checks proxy settings gathered from the environment, if specified,
or from the MacOSX framework SystemConfiguration.
"""
proxies = getproxies_environment()
if proxies:
return proxy_bypass_environment(host, proxies)
else: else:
return proxy_bypass_macosx_sysconf(host) return proxy_bypass_macosx_sysconf(host)
@ -2677,14 +2700,15 @@ elif os.name == 'nt':
return 0 return 0
def proxy_bypass(host): def proxy_bypass(host):
"""Return a dictionary of scheme -> proxy server URL mappings. """Return True, if host should be bypassed.
Returns settings gathered from the environment, if specified, Checks proxy settings gathered from the environment, if specified,
or the registry. or the registry.
""" """
if getproxies_environment(): proxies = getproxies_environment()
return proxy_bypass_environment(host) if proxies:
return proxy_bypass_environment(host, proxies)
else: else:
return proxy_bypass_registry(host) return proxy_bypass_registry(host)

View File

@ -673,6 +673,7 @@ Kjetil Jacobsen
Bertrand Janin Bertrand Janin
Geert Jansen Geert Jansen
Jack Jansen Jack Jansen
Hans-Peter Jansen
Bill Janssen Bill Janssen
Thomas Jarosch Thomas Jarosch
Juhana Jauhiainen Juhana Jauhiainen

View File

@ -256,6 +256,10 @@ Core and Builtins
Library Library
------- -------
- Issue #26804: urllib.request will prefer lower_case proxy environment
variables over UPPER_CASE or Mixed_Case ones. Patch contributed by Hans-Peter
Jansen.
- Issue #26837: assertSequenceEqual() now correctly outputs non-stringified - Issue #26837: assertSequenceEqual() now correctly outputs non-stringified
differing items (like bytes in the -b mode). This affects assertListEqual() differing items (like bytes in the -b mode). This affects assertListEqual()
and assertTupleEqual(). and assertTupleEqual().