diff --git a/dulwich/client.py b/dulwich/client.py index 044457026..a529ff686 100644 --- a/dulwich/client.py +++ b/dulwich/client.py @@ -50,8 +50,10 @@ try: from urllib import quote as urlquote + from urllib import unquote as urlunquote except ImportError: from urllib.parse import quote as urlquote + from urllib.parse import unquote as urlunquote try: import urllib2 @@ -1064,7 +1066,11 @@ def get_url(self, path): def from_parsedurl(cls, parsedurl, **kwargs): auth, host = urllib2.splituser(parsedurl.netloc) password = parsedurl.password + if password is not None: + password = urlunquote(password) username = parsedurl.username + if username is not None: + username = urlunquote(username) # TODO(jelmer): This also strips the username parsedurl = parsedurl._replace(netloc=host) return cls(urlparse.urlunparse(parsedurl), diff --git a/dulwich/tests/test_client.py b/dulwich/tests/test_client.py index 59ac959fd..f20030a70 100644 --- a/dulwich/tests/test_client.py +++ b/dulwich/tests/test_client.py @@ -23,6 +23,15 @@ import shutil import tempfile +try: + from urllib import quote as urlquote +except ImportError: + from urllib.parse import quote as urlquote + +try: + import urlparse +except ImportError: + import urllib.parse as urlparse import dulwich from dulwich import ( @@ -819,6 +828,28 @@ def test_init_no_username_passwd(self): h for h in c.opener.handlers if getattr(h, 'passwd', None) is not None] self.assertEqual(0, len(pw_handler)) + def test_from_parsedurl_on_url_with_quoted_credentials(self): + original_username = 'john|the|first' + quoted_username = urlquote(original_username) + + original_password = 'Ya#1$2%3' + quoted_password = urlquote(original_password) + + url = 'https://{username}:{password}@github.com/jelmer/dulwich'.format( + username=quoted_username, + password=quoted_password + ) + + c = HttpGitClient.from_parsedurl(urlparse.urlparse(url)) + self.assertEqual(original_username, c._username) + self.assertEqual(original_password, c._password) + [pw_handler] = [ + h for h in c.opener.handlers if getattr(h, 'passwd', None) is not None] + self.assertEqual( + (original_username, original_password), + pw_handler.passwd.find_user_password( + None, 'https://github.com/jelmer/dulwich')) + class TCPGitClientTests(TestCase):