Skip to content

Commit

Permalink
Merge pull request #5657 from cjerdonek/misc-add-split-auth-from-url
Browse files Browse the repository at this point in the history
Add split_auth_from_netloc() to misc.py
  • Loading branch information
pradyunsg authored Jul 27, 2018
2 parents 1a9128d + 58b21d1 commit d77e329
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 30 deletions.
Empty file.
29 changes: 26 additions & 3 deletions src/pip/_internal/utils/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,19 +852,42 @@ def enum(*sequential, **named):
return type('Enum', (), enums)


def split_auth_from_netloc(netloc):
"""
Parse out and remove the auth information from a netloc.
Returns: (netloc, (username, password)).
"""
if '@' not in netloc:
return netloc, (None, None)

# Split from the right because that's how urllib.parse.urlsplit()
# behaves if more than one @ is present (which can be checked using
# the password attribute of urlsplit()'s return value).
auth, netloc = netloc.rsplit('@', 1)
if ':' in auth:
# Split from the left because that's how urllib.parse.urlsplit()
# behaves if more than one : is present (which again can be checked
# using the password attribute of the return value)
user_pass = tuple(auth.split(':', 1))
else:
user_pass = auth, None

return netloc, user_pass


def remove_auth_from_url(url):
# Return a copy of url with 'username:password@' removed.
# username/pass params are passed to subversion through flags
# and are not recognized in the url.

# parsed url
purl = urllib_parse.urlsplit(url)
stripped_netloc = \
purl.netloc.split('@')[-1]
netloc, user_pass = split_auth_from_netloc(purl.netloc)

# stripped url
url_pieces = (
purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment
purl.scheme, netloc, purl.path, purl.query, purl.fragment
)
surl = urllib_parse.urlunsplit(url_pieces)
return surl
Expand Down
27 changes: 6 additions & 21 deletions src/pip/_internal/vcs/subversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

from pip._internal.models.link import Link
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import display_path, rmtree
from pip._internal.utils.misc import (
display_path, rmtree, split_auth_from_netloc,
)
from pip._internal.vcs import VersionControl, vcs

_svn_xml_url_re = re.compile('url="([^"]+)"')
Expand Down Expand Up @@ -102,27 +104,10 @@ def get_revision(self, location):

def get_netloc_and_auth(self, netloc):
"""
Parse out and remove from the netloc the auth information.
This allows the auth information to be provided via the --username
and --password options instead of via the URL.
This override allows the auth information to be passed to svn via the
--username and --password options instead of via the URL.
"""
if '@' not in netloc:
return netloc, (None, None)

# Split from the right because that's how urllib.parse.urlsplit()
# behaves if more than one @ is present (by checking the password
# attribute of urlsplit()'s return value).
auth, netloc = netloc.rsplit('@', 1)
if ':' in auth:
# Split from the left because that's how urllib.parse.urlsplit()
# behaves if more than one : is present (again by checking the
# password attribute of the return value)
user_pass = tuple(auth.split(':', 1))
else:
user_pass = auth, None

return netloc, user_pass
return split_auth_from_netloc(netloc)

def get_url_rev_and_auth(self, url):
# hotfix the URL scheme after removing svn+ from svn+ssh:// readd it
Expand Down
23 changes: 21 additions & 2 deletions tests/unit/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
from pip._internal.utils.hashes import Hashes, MissingHashes
from pip._internal.utils.misc import (
call_subprocess, egg_link_path, ensure_dir, get_installed_distributions,
get_prog, normalize_path, remove_auth_from_url, rmtree, untar_file,
unzip_file,
get_prog, normalize_path, remove_auth_from_url, rmtree,
split_auth_from_netloc, untar_file, unzip_file,
)
from pip._internal.utils.packaging import check_dist_requires_python
from pip._internal.utils.temp_dir import TempDirectory
Expand Down Expand Up @@ -627,6 +627,25 @@ def test_call_subprocess_closes_stdin():
call_subprocess([sys.executable, '-c', 'input()'])


@pytest.mark.parametrize('netloc, expected', [
# Test a basic case.
('example.com', ('example.com', (None, None))),
# Test with username and no password.
('user@example.com', ('example.com', ('user', None))),
# Test with username and password.
('user:pass@example.com', ('example.com', ('user', 'pass'))),
# Test with username and empty password.
('user:@example.com', ('example.com', ('user', ''))),
# Test the password containing an @ symbol.
('user:pass@word@example.com', ('example.com', ('user', 'pass@word'))),
# Test the password containing a : symbol.
('user:pass:word@example.com', ('example.com', ('user', 'pass:word'))),
])
def test_split_auth_from_netloc(netloc, expected):
actual = split_auth_from_netloc(netloc)
assert actual == expected


@pytest.mark.parametrize('auth_url, expected_url', [
('https://user:pass@domain.tld/project/tags/v0.2',
'https://domain.tld/project/tags/v0.2'),
Expand Down
4 changes: 0 additions & 4 deletions tests/unit/test_vcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,6 @@ def test_git__get_netloc_and_auth(netloc, expected):
('user@example.com', ('example.com', ('user', None))),
# Test with username and password.
('user:pass@example.com', ('example.com', ('user', 'pass'))),
# Test the password containing an @ symbol.
('user:pass@word@example.com', ('example.com', ('user', 'pass@word'))),
# Test the password containing a : symbol.
('user:pass:word@example.com', ('example.com', ('user', 'pass:word'))),
])
def test_subversion__get_netloc_and_auth(netloc, expected):
"""
Expand Down

0 comments on commit d77e329

Please sign in to comment.