clonebundles: filter out invalid schemes instead of failing on them stable
authorMathias De Mare <mathias.de_mare@nokia.com>
Thu, 20 Apr 2023 11:23:45 +0200
branchstable
changeset 50371 7b723217d368
parent 50370 ef7f943ebabf
child 50372 164b6c4878b8
clonebundles: filter out invalid schemes instead of failing on them Previously, an invalid clonebundle scheme would result in a failed clone. By specifying a list of schemes we support, we can make sure adding a new scheme (like the one for inline clonebundles) does not result in clones failing for older clients.
mercurial/bundlecaches.py
mercurial/wireprotov1server.py
tests/test-clonebundles.t
--- a/mercurial/bundlecaches.py	Thu Apr 20 10:48:12 2023 +0200
+++ b/mercurial/bundlecaches.py	Thu Apr 20 11:23:45 2023 +0200
@@ -24,6 +24,11 @@
 urlreq = util.urlreq
 
 CB_MANIFEST_FILE = b'clonebundles.manifest'
+SUPPORTED_CLONEBUNDLE_SCHEMES = [
+    b"http://",
+    b"https://",
+    b"largefile://",
+]
 
 
 @attr.s
@@ -337,7 +342,9 @@
     return False
 
 
-def filterclonebundleentries(repo, entries, streamclonerequested=False):
+def filterclonebundleentries(
+    repo, entries, streamclonerequested=False, pullbundles=False
+):
     """Remove incompatible clone bundle manifest entries.
 
     Accepts a list of entries parsed with ``parseclonebundlesmanifest``
@@ -349,6 +356,16 @@
     """
     newentries = []
     for entry in entries:
+        url = entry.get(b'URL')
+        if not pullbundles and not any(
+            [url.startswith(scheme) for scheme in SUPPORTED_CLONEBUNDLE_SCHEMES]
+        ):
+            repo.ui.debug(
+                b'filtering %s because not a supported clonebundle scheme\n'
+                % url
+            )
+            continue
+
         spec = entry.get(b'BUNDLESPEC')
         if spec:
             try:
@@ -358,8 +375,7 @@
                 # entries.
                 if streamclonerequested and not isstreamclonespec(bundlespec):
                     repo.ui.debug(
-                        b'filtering %s because not a stream clone\n'
-                        % entry[b'URL']
+                        b'filtering %s because not a stream clone\n' % url
                     )
                     continue
 
@@ -369,7 +385,7 @@
             except error.UnsupportedBundleSpecification as e:
                 repo.ui.debug(
                     b'filtering %s because unsupported bundle '
-                    b'spec: %s\n' % (entry[b'URL'], stringutil.forcebytestr(e))
+                    b'spec: %s\n' % (url, stringutil.forcebytestr(e))
                 )
                 continue
         # If we don't have a spec and requested a stream clone, we don't know
@@ -377,14 +393,12 @@
         elif streamclonerequested:
             repo.ui.debug(
                 b'filtering %s because cannot determine if a stream '
-                b'clone bundle\n' % entry[b'URL']
+                b'clone bundle\n' % url
             )
             continue
 
         if b'REQUIRESNI' in entry and not sslutil.hassni:
-            repo.ui.debug(
-                b'filtering %s because SNI not supported\n' % entry[b'URL']
-            )
+            repo.ui.debug(b'filtering %s because SNI not supported\n' % url)
             continue
 
         if b'REQUIREDRAM' in entry:
@@ -392,15 +406,14 @@
                 requiredram = util.sizetoint(entry[b'REQUIREDRAM'])
             except error.ParseError:
                 repo.ui.debug(
-                    b'filtering %s due to a bad REQUIREDRAM attribute\n'
-                    % entry[b'URL']
+                    b'filtering %s due to a bad REQUIREDRAM attribute\n' % url
                 )
                 continue
             actualram = repo.ui.estimatememory()
             if actualram is not None and actualram * 0.66 < requiredram:
                 repo.ui.debug(
                     b'filtering %s as it needs more than 2/3 of system memory\n'
-                    % entry[b'URL']
+                    % url
                 )
                 continue
 
--- a/mercurial/wireprotov1server.py	Thu Apr 20 10:48:12 2023 +0200
+++ b/mercurial/wireprotov1server.py	Thu Apr 20 11:23:45 2023 +0200
@@ -380,7 +380,7 @@
     if not manifest:
         return None
     res = bundlecaches.parseclonebundlesmanifest(repo, manifest)
-    res = bundlecaches.filterclonebundleentries(repo, res)
+    res = bundlecaches.filterclonebundleentries(repo, res, pullbundles=True)
     if not res:
         return None
     cl = repo.unfiltered().changelog
--- a/tests/test-clonebundles.t	Thu Apr 20 10:48:12 2023 +0200
+++ b/tests/test-clonebundles.t	Thu Apr 20 11:23:45 2023 +0200
@@ -62,11 +62,16 @@
 Manifest file with URL with unknown scheme skips the URL
   $ echo 'weirdscheme://does.not.exist/bundle.hg' > server/.hg/clonebundles.manifest
   $ hg clone http://localhost:$HGPORT unknown-scheme
-  applying clone bundle from weirdscheme://does.not.exist/bundle.hg (known-bad-output !)
-  error fetching bundle: unknown url type: weirdscheme (known-bad-output !)
-  abort: error applying bundle (known-bad-output !)
-  (if this error persists, consider contacting the server operator or disable clone bundles via "--config ui.clonebundles=false") (known-bad-output !)
-  [255]
+  no compatible clone bundles available on server; falling back to regular clone
+  (you may want to report this to the server operator)
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 2 files
+  new changesets 53245c60e682:aaff8d2ffbbf
+  updating to branch default
+  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 
 Server is not running aborts