ソースを参照

client: Handle absolute path as redirect location in HTTP client

Some git servers can redirect a repository URL using an absolute-path URI reference
as value of the Location HTTP header as allowed by RFC 7231 Section 7.1.2.

That edge case was causing dulwich to raise urllib3.exceptions.LocationValueError
when attempting to clone such repository as the redirection URL was missing the
scheme and the net location.

Fix the issue by restoring scheme and net location to the redirection URL using
those from the original request URL.
Antoine Lambert 2 年 前
コミット
7fd6431c57
2 ファイル変更18 行追加4 行削除
  1. 1 1
      dulwich/client.py
  2. 17 3
      dulwich/tests/test_client.py

+ 1 - 1
dulwich/client.py

@@ -1947,7 +1947,7 @@ class AbstractHttpGitClient(GitClient):
                     "Redirected from URL %s to URL %s without %s"
                     % (url, resp.redirect_location, tail)
                 )
-            base_url = resp.redirect_location[: -len(tail)]
+            base_url = urljoin(url, resp.redirect_location[: -len(tail)])
 
         try:
             self.dumb = (

+ 17 - 3
dulwich/tests/test_client.py

@@ -1042,6 +1042,7 @@ class HttpGitClientTests(TestCase):
 
         test_data = {
             "https://gitlab.com/inkscape/inkscape/": {
+                "location": "https://gitlab.com/inkscape/inkscape.git/",
                 "redirect_url": "https://gitlab.com/inkscape/inkscape.git/",
                 "refs_data": (
                     b"001e# service=git-upload-pack\n00000032"
@@ -1050,6 +1051,7 @@ class HttpGitClientTests(TestCase):
                 ),
             },
             "https://github.com/jelmer/dulwich/": {
+                "location": "https://github.com/jelmer/dulwich/",
                 "redirect_url": "https://github.com/jelmer/dulwich/",
                 "refs_data": (
                     b"001e# service=git-upload-pack\n00000032"
@@ -1057,6 +1059,16 @@ class HttpGitClientTests(TestCase):
                     b"HEAD\n0000"
                 ),
             },
+            # check for absolute-path URI reference as location
+            "https://codeberg.org/ashwinvis/radicale-sh.git/": {
+                "location": "/ashwinvis/radicale-auth-sh/",
+                "redirect_url": "https://codeberg.org/ashwinvis/radicale-auth-sh/",
+                "refs_data": (
+                    b"001e# service=git-upload-pack\n00000032"
+                    b"470f8603768b608fc988675de2fae8f963c21158 "
+                    b"HEAD\n0000"
+                ),
+            },
         }
 
         tail = "info/refs?service=git-upload-pack"
@@ -1069,7 +1081,7 @@ class HttpGitClientTests(TestCase):
 
             def request(self, method, url, fields=None, headers=None, redirect=True, preload_content=True):
                 base_url = url[: -len(tail)]
-                redirect_base_url = test_data[base_url]["redirect_url"]
+                redirect_base_url = test_data[base_url]["location"]
                 redirect_url = redirect_base_url + tail
                 headers = {
                     "Content-Type": "application/x-git-upload-pack-advertisement"
@@ -1083,8 +1095,9 @@ class HttpGitClientTests(TestCase):
                     request_url = url
                     if redirect_base_url != base_url:
                         body = b""
-                        headers["location"] = redirect_url
+                        headers["location"] = test_data[base_url]["location"]
                         status = 301
+
                 return HTTPResponse(
                     body=BytesIO(body),
                     headers=headers,
@@ -1107,12 +1120,13 @@ class HttpGitClientTests(TestCase):
 
             # check expected behavior of urllib3
             redirect_location = resp.get_redirect_location()
+
             if resp.status == 200:
                 self.assertFalse(redirect_location)
 
             if redirect_location:
                 # check that url redirection has been correctly detected
-                self.assertEqual(processed_url, redirect_location[: -len(tail)])
+                self.assertEqual(processed_url, test_data[base_url]["redirect_url"])
             else:
                 # check also the no redirection case
                 self.assertEqual(processed_url, base_url)