[Python-checkins] cpython (merge 3.1 -> 3.2): Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP

ronald.oussoren python-checkins at python.org
Mon Mar 14 23:54:26 CET 2011


http://hg.python.org/cpython/rev/aafb0fed1811
changeset:   68474:aafb0fed1811
branch:      3.2
parent:      68471:f6cab3819160
parent:      68473:682903e066db
user:        Ronald Oussoren <ronaldoussoren at mac.com>
date:        Mon Mar 14 18:46:50 2011 -0400
summary:
  Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified IP addresses in the proxy exception list.

files:
  Lib/dbm/__init__.py
  Lib/test/test_dbm.py
  Lib/test/test_urllib2.py
  Lib/urllib/request.py
  Misc/ACKS
  Misc/NEWS

diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -7,7 +7,9 @@
 import array
 
 import urllib.request
-from urllib.request import Request, OpenerDirector
+# The proxy bypass method imported below has logic specific to the OSX
+# proxy config data structure but is testable on all platforms.
+from urllib.request import Request, OpenerDirector, _proxy_bypass_macosx_sysconf
 
 # XXX
 # Request
@@ -1076,6 +1078,17 @@
         self.assertEqual(req.get_host(), "www.python.org")
         del os.environ['no_proxy']
 
+    def test_proxy_no_proxy_all(self):
+        os.environ['no_proxy'] = '*'
+        o = OpenerDirector()
+        ph = urllib.request.ProxyHandler(dict(http="proxy.example.com"))
+        o.add_handler(ph)
+        req = Request("http://www.python.org")
+        self.assertEqual(req.get_host(), "www.python.org")
+        r = o.open(req)
+        self.assertEqual(req.get_host(), "www.python.org")
+        del os.environ['no_proxy']
+
 
     def test_proxy_https(self):
         o = OpenerDirector()
@@ -1116,6 +1129,26 @@
         self.assertEqual(req.get_host(), "proxy.example.com:3128")
         self.assertEqual(req.get_header("Proxy-authorization"),"FooBar")
 
+    def test_osx_proxy_bypass(self):
+        bypass = {
+            'exclude_simple': False,
+            'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.10',
+                           '10.0/16']
+        }
+        # Check hosts that should trigger the proxy bypass
+        for host in ('foo.bar', 'www.bar.com', '127.0.0.1', '10.10.0.1',
+                     '10.0.0.1'):
+            self.assertTrue(_proxy_bypass_macosx_sysconf(host, bypass),
+                            'expected bypass of %s to be True' % host)
+        # Check hosts that should not trigger the proxy bypass
+        for host in ('abc.foo.bar', 'bar.com', '127.0.0.2', '10.11.0.1', 'test'):
+            self.assertFalse(_proxy_bypass_macosx_sysconf(host, bypass),
+                             'expected bypass of %s to be False' % host)
+
+        # Check the exclude_simple flag
+        bypass = {'exclude_simple': True, 'exceptions': []}
+        self.assertTrue(_proxy_bypass_macosx_sysconf('test', bypass))
+
     def test_basic_auth(self, quote_char='"'):
         opener = OpenerDirector()
         password_manager = MockPasswordManager()
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -2208,68 +2208,76 @@
     return 0
 
 
+# This code tests an OSX specific data structure but is testable on all
+# platforms
+def _proxy_bypass_macosx_sysconf(host, proxy_settings):
+    """
+    Return True iff this host shouldn't be accessed using a proxy
+
+    This function uses the MacOSX framework SystemConfiguration
+    to fetch the proxy information.
+
+    proxy_settings come from _scproxy._get_proxy_settings or get mocked ie:
+    { 'exclude_simple': bool,
+      'exceptions': ['foo.bar', '*.bar.com', '127.0.0.1', '10.1', '10.0/16']
+    }
+    """
+    import re
+    import socket
+    from fnmatch import fnmatch
+
+    hostonly, port = splitport(host)
+
+    def ip2num(ipAddr):
+        parts = ipAddr.split('.')
+        parts = list(map(int, parts))
+        if len(parts) != 4:
+            parts = (parts + [0, 0, 0, 0])[:4]
+        return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
+
+    # Check for simple host names:
+    if '.' not in host:
+        if proxy_settings['exclude_simple']:
+            return True
+
+    hostIP = None
+
+    for value in proxy_settings.get('exceptions', ()):
+        # Items in the list are strings like these: *.local, 169.254/16
+        if not value: continue
+
+        m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
+        if m is not None:
+            if hostIP is None:
+                try:
+                    hostIP = socket.gethostbyname(hostonly)
+                    hostIP = ip2num(hostIP)
+                except socket.error:
+                    continue
+
+            base = ip2num(m.group(1))
+            mask = m.group(2)
+            if mask is None:
+                mask = 8 * (m.group(1).count('.') + 1)
+            else:
+                mask = int(mask[1:])
+            mask = 32 - mask
+
+            if (hostIP >> mask) == (base >> mask):
+                return True
+
+        elif fnmatch(host, value):
+            return True
+
+    return False
+
+
 if sys.platform == 'darwin':
     from _scproxy import _get_proxy_settings, _get_proxies
 
     def proxy_bypass_macosx_sysconf(host):
-        """
-        Return True iff this host shouldn't be accessed using a proxy
-
-        This function uses the MacOSX framework SystemConfiguration
-        to fetch the proxy information.
-        """
-        import re
-        import socket
-        from fnmatch import fnmatch
-
-        hostonly, port = splitport(host)
-
-        def ip2num(ipAddr):
-            parts = ipAddr.split('.')
-            parts = list(map(int, parts))
-            if len(parts) != 4:
-                parts = (parts + [0, 0, 0, 0])[:4]
-            return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3]
-
         proxy_settings = _get_proxy_settings()
-
-        # Check for simple host names:
-        if '.' not in host:
-            if proxy_settings['exclude_simple']:
-                return True
-
-        hostIP = None
-
-        for value in proxy_settings.get('exceptions', ()):
-            # Items in the list are strings like these: *.local, 169.254/16
-            if not value: continue
-
-            m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value)
-            if m is not None:
-                if hostIP is None:
-                    try:
-                        hostIP = socket.gethostbyname(hostonly)
-                        hostIP = ip2num(hostIP)
-                    except socket.error:
-                        continue
-
-                base = ip2num(m.group(1))
-                mask = m.group(2)
-                if mask is None:
-                    mask = 8 * (m.group(1).count('.') + 1)
-
-                else:
-                    mask = int(mask[1:])
-                    mask = 32 - mask
-
-                if (hostIP >> mask) == (base >> mask):
-                    return True
-
-            elif fnmatch(host, value):
-                return True
-
-        return False
-
+        return _proxy_bypass_macosx_sysconf(host, proxy_settings)
 
     def getproxies_macosx_sysconf():
         """Return a dictionary of scheme -> proxy server URL mappings.
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -34,6 +34,9 @@
 Library
 -------
 
+- Issue #11500: Fixed a bug in the os x proxy bypass code for fully qualified 
+  IP addresses in the proxy exception list. 
+
 - Issue #11491: dbm.error is no longer raised when dbm.open is called with
   the "n" as the flag argument and the file exists. The behavior matches
   the documentation and general logic.

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list