]> granicus.if.org Git - python/commitdiff
Patch #1496206: urllib2 PasswordMgr ./. default ports
authorGeorg Brandl <georg@python.org>
Sun, 28 May 2006 20:23:12 +0000 (20:23 +0000)
committerGeorg Brandl <georg@python.org>
Sun, 28 May 2006 20:23:12 +0000 (20:23 +0000)
Lib/test/test_urllib2.py
Lib/urllib2.py
Misc/NEWS

index 9203e37fb6a809e43a97234bf85c71fb15e2dd21..32cc6128e9bbd593e1385419372954c9534e305f 100644 (file)
@@ -76,10 +76,11 @@ def test_password_manager(self):
     >>> mgr.find_user_password("c", "http://example.com/bar")
     ('bar', 'nini')
 
-    Currently, we use the highest-level path where more than one match:
+    Actually, this is really undefined ATM
+##     Currently, we use the highest-level path where more than one match:
 
-    >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
-    ('joe', 'password')
+##     >>> mgr.find_user_password("Some Realm", "http://example.com/ni")
+##     ('joe', 'password')
 
     Use latest add_password() in case of conflict:
 
@@ -110,6 +111,53 @@ def test_password_manager(self):
     pass
 
 
+def test_password_manager_default_port(self):
+    """
+    >>> mgr = urllib2.HTTPPasswordMgr()
+    >>> add = mgr.add_password
+
+    The point to note here is that we can't guess the default port if there's
+    no scheme.  This applies to both add_password and find_user_password.
+
+    >>> add("f", "http://g.example.com:80", "10", "j")
+    >>> add("g", "http://h.example.com", "11", "k")
+    >>> add("h", "i.example.com:80", "12", "l")
+    >>> add("i", "j.example.com", "13", "m")
+    >>> mgr.find_user_password("f", "g.example.com:100")
+    (None, None)
+    >>> mgr.find_user_password("f", "g.example.com:80")
+    ('10', 'j')
+    >>> mgr.find_user_password("f", "g.example.com")
+    (None, None)
+    >>> mgr.find_user_password("f", "http://g.example.com:100")
+    (None, None)
+    >>> mgr.find_user_password("f", "http://g.example.com:80")
+    ('10', 'j')
+    >>> mgr.find_user_password("f", "http://g.example.com")
+    ('10', 'j')
+    >>> mgr.find_user_password("g", "h.example.com")
+    ('11', 'k')
+    >>> mgr.find_user_password("g", "h.example.com:80")
+    ('11', 'k')
+    >>> mgr.find_user_password("g", "http://h.example.com:80")
+    ('11', 'k')
+    >>> mgr.find_user_password("h", "i.example.com")
+    (None, None)
+    >>> mgr.find_user_password("h", "i.example.com:80")
+    ('12', 'l')
+    >>> mgr.find_user_password("h", "http://i.example.com:80")
+    ('12', 'l')
+    >>> mgr.find_user_password("i", "j.example.com")
+    ('13', 'm')
+    >>> mgr.find_user_password("i", "j.example.com:80")
+    (None, None)
+    >>> mgr.find_user_password("i", "http://j.example.com")
+    ('13', 'm')
+    >>> mgr.find_user_password("i", "http://j.example.com:80")
+    (None, None)
+
+    """
+
 class MockOpener:
     addheaders = []
     def open(self, req, data=None):
index cdb3a22b3799de5b70fe454f955bcd7dd6a5191a..b2ff04fc6cdef435946b56d71affba8a143ed553 100644 (file)
@@ -695,32 +695,45 @@ class HTTPPasswordMgr:
         # uri could be a single URI or a sequence
         if isinstance(uri, basestring):
             uri = [uri]
-        uri = tuple(map(self.reduce_uri, uri))
         if not realm in self.passwd:
             self.passwd[realm] = {}
-        self.passwd[realm][uri] = (user, passwd)
+        for default_port in True, False:
+            reduced_uri = tuple(
+                [self.reduce_uri(u, default_port) for u in uri])
+            self.passwd[realm][reduced_uri] = (user, passwd)
 
     def find_user_password(self, realm, authuri):
         domains = self.passwd.get(realm, {})
-        authuri = self.reduce_uri(authuri)
-        for uris, authinfo in domains.iteritems():
-            for uri in uris:
-                if self.is_suburi(uri, authuri):
-                    return authinfo
+        for default_port in True, False:
+            reduced_authuri = self.reduce_uri(authuri, default_port)
+            for uris, authinfo in domains.iteritems():
+                for uri in uris:
+                    if self.is_suburi(uri, reduced_authuri):
+                        return authinfo
         return None, None
 
-    def reduce_uri(self, uri):
-        """Accept netloc or URI and extract only the netloc and path"""
+    def reduce_uri(self, uri, default_port=True):
+        """Accept authority or URI and extract only the authority and path."""
+        # note HTTP URLs do not have a userinfo component
         parts = urlparse.urlsplit(uri)
         if parts[1]:
             # URI
-            return parts[1], parts[2] or '/'
-        elif parts[0]:
-            # host:port
-            return uri, '/'
+            scheme = parts[0]
+            authority = parts[1]
+            path = parts[2] or '/'
         else:
-            # host
-            return parts[2], '/'
+            # host or host:port
+            scheme = None
+            authority = uri
+            path = '/'
+        host, port = splitport(authority)
+        if default_port and port is None and scheme is not None:
+            dport = {"http": 80,
+                     "https": 443,
+                     }.get(scheme)
+            if dport is not None:
+                authority = "%s:%d" % (host, dport)
+        return authority, path
 
     def is_suburi(self, base, test):
         """Check if test is below base in a URI tree
index 31a5af9302743e875224a840f5f8a0b2c8ae5392..90407d6386736ab55150d620a12a46cecc2ff170 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -85,6 +85,9 @@ Extension Modules
 Library
 -------
 
+- Patch #1496206: improve urllib2 handling of passwords with respect to
+  default HTTP and HTTPS ports.
+
 - Patch #1080727: add "encoding" parameter to doctest.DocFileSuite.
 
 - Patch #1281707: speed up gzip.readline.