diff --git a/README.rst b/README.rst index 6573f4c..2938bcf 100644 --- a/README.rst +++ b/README.rst @@ -162,7 +162,7 @@ URL schema +----------------------+-----------------------------------------------+--------------------------------------------------+ | MSSQL [5]_ | ``mssql`` | ``mssqlms://USER:PASSWORD@HOST:PORT/NAME`` | +----------------------+-----------------------------------------------+--------------------------------------------------+ -| MySQL | ``django.db.backends.mysql`` | ``mysql://USER:PASSWORD@HOST:PORT/NAME`` | +| MySQL | ``django.db.backends.mysql`` | ``mysql://USER:PASSWORD@HOST:PORT/NAME`` [2]_ | +----------------------+-----------------------------------------------+--------------------------------------------------+ | MySQL (GIS) | ``django.contrib.gis.db.backends.mysql`` | ``mysqlgis://USER:PASSWORD@HOST:PORT/NAME`` | +----------------------+-----------------------------------------------+--------------------------------------------------+ @@ -185,9 +185,10 @@ URL schema .. [1] The django.db.backends.postgresql backend is named django.db.backends.postgresql_psycopg2 in older releases. For backwards compatibility, the old name still works in newer versions. (The new name does not work in older versions). -.. [2] With PostgreSQL, you can also use unix domain socket paths with +.. [2] With PostgreSQL or CloudSQL, you can also use unix domain socket paths with `percent encoding `_: - ``postgres://%2Fvar%2Flib%2Fpostgresql/dbname``. + ``postgres://%2Fvar%2Flib%2Fpostgresql/dbname`` + ``mysql://uf07k1i6d8ia0v@%2fcloudsql%2fproject%3alocation%3ainstance/dbname`` .. [3] SQLite connects to file based databases. The same URL format is used, omitting the hostname, and using the "file" portion as the filename of the database. This has the effect of four slashes being present for an absolute file path: diff --git a/dj_database_url.py b/dj_database_url.py index ae795b1..d2a9f01 100644 --- a/dj_database_url.py +++ b/dj_database_url.py @@ -102,14 +102,15 @@ def parse( # Handle postgres percent-encoded paths. hostname = url.hostname or "" - if "%2f" in hostname.lower(): + if "%" in hostname: # Switch to url.netloc to avoid lower cased paths hostname = url.netloc if "@" in hostname: hostname = hostname.rsplit("@", 1)[1] if ":" in hostname: hostname = hostname.split(":", 1)[0] - hostname = hostname.replace("%2f", "/").replace("%2F", "/") + # Use URL Parse library to decode % encodes + hostname = urlparse.unquote(hostname) # Lookup specified engine. engine = SCHEMES[url.scheme] if engine is None else engine diff --git a/test_dj_database_url.py b/test_dj_database_url.py index c76c816..7ad601c 100644 --- a/test_dj_database_url.py +++ b/test_dj_database_url.py @@ -38,6 +38,17 @@ def test_postgres_unix_socket_parsing(self): assert url["PASSWORD"] == "" assert url["PORT"] == "" + def test_postgres_google_cloud_parsing(self): + url = "postgres://uf07k1i6d8ia0v:wegauwhgeuioweg@%2Fcloudsql%2Fproject_id%3Aregion%3Ainstance_id/d8r82722r2kuvn" + url = dj_database_url.parse(url) + + assert url["ENGINE"] == "django.db.backends.postgresql" + assert url["NAME"] == "d8r82722r2kuvn" + assert url["HOST"] == "/cloudsql/project_id:region:instance_id" + assert url["USER"] == "uf07k1i6d8ia0v" + assert url["PASSWORD"] == "wegauwhgeuioweg" + assert url["PORT"] == "" + def test_ipv6_parsing(self): url = "postgres://ieRaekei9wilaim7:wegauwhgeuioweg@[2001:db8:1234::1234:5678:90af]:5431/d8r82722r2kuvn" url = dj_database_url.parse(url)