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.
--- 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