Bug in web.db.dburl2dict: it doesn't work if password contains '@'

17 views
Skip to first unread message

Zhang Huangbin

unread,
Aug 7, 2012, 9:19:46 AM8/7/12
to we...@googlegroups.com
With last commit, we have function web.database.dburl2dict. but it doesn't work if password contains '@'.

>>> dburl2dict('postgres://james:"pw_with_@"@serverfarm.example.net:5432/mygreatdb')
{'host': '"@serverfarm.example.net', 'pw': '"pw_with_', ...}

As you can see, both host and pw are incorrect.

Michael Diamond

unread,
Aug 7, 2012, 9:42:37 AM8/7/12
to we...@googlegroups.com

Michael Diamond
dim...@gmail.com
www.DigitalGemstones.com


You can't have an unescaped  '@' character in a URL for this very reason - the character has a special meaning, and leaving it clear makes parsing the URL ambiguous: http://en.wikipedia.org/wiki/Uniform_resource_locator#List_of_allowed_URL_characters

Java's URL class makes the same parsing decision (URL doesn't accept postgres so I switched it to http):

    URL u = new URL("http://james:\"pw_with_@\"@serverfarm.example.net:5432/mygreatdb");
    System.out.println(u.getHost());        # "@serverfarm.example.net
    System.out.println(u.getUserInfo());        # james:"pw_with_

The correct solution is to escape your password before passing it to dburl2dict, probably using http://docs.python.org/library/urllib#urllib.quote_plus (may want to pass '' as the second argument, to also escape '/' characters), since there's no way for dburl2dict to know how to "properly" parse your malformed URL.

Michael

Zhang Huangbin

unread,
Aug 7, 2012, 9:46:29 AM8/7/12
to we...@googlegroups.com
DIRTY path to fix it and add "port":

diff --git a/web/db.py b/web/db.py
index a51fa7a..66b7cf1 100644
--- a/web/db.py
+++ b/web/db.py
@@ -1139,13 +1139,23 @@ def dburl2dict(url):
         {'user': 'james', 'host': 'serverfarm.example.net', 'db': 'mygreatdb', 'pw': 'day', 'dbn': 'postgres'}
     
     """
+    import re
     dbn, rest = url.split('://', 1)
     user, rest = rest.split(':', 1)
-    pw, rest = rest.split('@', 1)
+    user = re.sub("""['"]""", '', user)
+    if rest.startswith('"'):
+        pw, rest = rest.split('"', 2)[1:]
+        rest = rest.split('@', 1)[1]
+    elif rest.startswith("'"):
+        pw, rest = rest.split("'", 2)[1:]
+        rest = rest.split('@', 1)[1]
+    else:
+        pw, rest = rest.split('@', 1)
+
     host, rest = rest.split(':', 1)
     port, rest = rest.split('/', 1)
     db = rest
-    return dict(dbn=dbn, user=user, pw=pw, db=db, host=host)
+    return dict(dbn=dbn, user=user, pw=pw, db=db, host=host, port=port)
 
 _databases = {}
 def database(dburl=None, **params):
Reply all
Reply to author
Forward
0 new messages