Skip to content

Commit

Permalink
Added support for parsing connection strings with special characters …
Browse files Browse the repository at this point in the history
…in the password and handling invalid IPv6 URLs. (#461)

* Added new tests for connection strings with special characters in password and invalid IPv6 password.

* Fix code style issue

---------

Co-authored-by: Serghei Iakovlev <egrep@protonmail.ch>
  • Loading branch information
MayGrass and sergeyklay authored Mar 31, 2023
1 parent 4294fb5 commit d1494c6
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
16 changes: 15 additions & 1 deletion environ/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from urllib.parse import (
parse_qs,
ParseResult,
quote,
unquote,
unquote_plus,
urlparse,
Expand Down Expand Up @@ -65,6 +66,10 @@ def _cast_urlstr(v):
return unquote(v) if isinstance(v, str) else v


def _urlparse_quote(url):
return urlparse(quote(url, safe=':/?&=@'))


class NoValue:
"""Represent of no value object."""

Expand Down Expand Up @@ -474,7 +479,9 @@ def parse_value(cls, value, cast):
return value

@classmethod
# pylint: disable=too-many-statements
def db_url_config(cls, url, engine=None):
# pylint: enable-msg=too-many-statements
"""Parse an arbitrary database URL.
Supports the following URL schemas:
Expand Down Expand Up @@ -509,10 +516,17 @@ def db_url_config(cls, url, engine=None):
'NAME': ':memory:'
}
# note: no other settings are required for sqlite
url = urlparse(url)
try:
url = urlparse(url)
# handle Invalid IPv6 URL
except ValueError:
url = _urlparse_quote(url)

config = {}

# handle unexpected URL schemes with special characters
if not url.path:
url = _urlparse_quote(urlunparse(url))
# Remove query strings.
path = url.path[1:]
path = unquote_plus(path.split('?', 2)[0])
Expand Down
18 changes: 18 additions & 0 deletions tests/test_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@
'enigma',
'secret',
12345),
# mysql://user:password@host:port/dbname
('mysql://enigma:><{~!@#$%^&*}[]@example.com:1234/dbname',
'django.db.backends.mysql',
'dbname',
'example.com',
'enigma',
'><{~!@#$%^&*}[]',
1234),
# mysql://user:password@host/dbname
('mysql://enigma:]password]@example.com/dbname',
'django.db.backends.mysql',
'dbname',
'example.com',
'enigma',
']password]',
''),
],
ids=[
'postgres',
Expand All @@ -149,6 +165,8 @@
'ldap',
'mssql',
'mssql_port',
'mysql_password_special_chars',
'mysql_invalid_ipv6_password',
],
)
def test_db_parsing(url, engine, name, host, user, passwd, port):
Expand Down

0 comments on commit d1494c6

Please sign in to comment.