diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt --- a/mercurial/help/config.txt +++ b/mercurial/help/config.txt @@ -1319,6 +1319,23 @@ Controls generic server settings. Instruct HTTP clients not to send request headers longer than this many bytes. (default: 1024) +``bundle1`` + Whether to allow clients to push and pull using the legacy bundle1 + exchange format. (default: True) + +``bundle1.push`` + Whether to allow clients to push using the legacy bundle1 exchange + format. (default: True) + +``bundle1.pull`` + Whether to allow clients to pull using the legacy bundle1 exchange + format. (default: True) + + Large repositories using the *generaldelta* storage format should + consider setting this option because converting *generaldelta* + repositories to the exchange format required by the bundle1 data + format can consume a lot of CPU. + ``smtp`` -------- diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py --- a/mercurial/wireproto.py +++ b/mercurial/wireproto.py @@ -30,6 +30,10 @@ from . import ( util, ) +bundle2required = _( + 'incompatible Mercurial client; bundle2 required\n' + '(see https://www.mercurial-scm.org/wiki/IncompatibleClient)\n') + class abstractserverproto(object): """abstract class that summarizes the protocol API @@ -487,6 +491,14 @@ def options(cmd, keys, others): % (cmd, ",".join(others))) return opts +def bundle1allowed(ui, action): + """Whether a bundle1 operation is allowed from the server.""" + v = ui.configbool('server', 'bundle1.%s' % action, None) + if v is not None: + return v + + return ui.configbool('server', 'bundle1', True) + # list of commands commands = {} @@ -652,6 +664,11 @@ def getbundle(repo, proto, others): elif keytype != 'plain': raise KeyError('unknown getbundle option type %s' % keytype) + + if not bundle1allowed(repo.ui, 'pull'): + if not exchange.bundle2requested(opts.get('bundlecaps')): + return ooberror(bundle2required) + cg = exchange.getbundle(repo, 'serve', **opts) return streamres(proto.groupchunks(cg)) @@ -763,6 +780,10 @@ def unbundle(repo, proto, heads): proto.getfile(fp) fp.seek(0) gen = exchange.readbundle(repo.ui, fp, None) + if (isinstance(gen, changegroupmod.cg1unpacker) + and not bundle1allowed(repo.ui, 'push')): + return ooberror(bundle2required) + r = exchange.unbundle(repo, gen, their_heads, 'serve', proto._client()) if util.safehasattr(r, 'addpart'): diff --git a/tests/test-bundle2-exchange.t b/tests/test-bundle2-exchange.t --- a/tests/test-bundle2-exchange.t +++ b/tests/test-bundle2-exchange.t @@ -951,3 +951,86 @@ Test lazily acquiring the lock during un remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files + + $ cd .. + +Servers can disable bundle1 for clone/pull operations + + $ killdaemons.py + $ hg init bundle2onlyserver + $ cd bundle2onlyserver + $ cat > .hg/hgrc << EOF + > [server] + > bundle1.pull = false + > EOF + + $ touch foo + $ hg -q commit -A -m initial + + $ hg serve -p $HGPORT -d --pid-file=hg.pid + $ cat hg.pid >> $DAEMON_PIDS + + $ hg --config experimental.bundle2-exp=false clone http://localhost:$HGPORT/ not-bundle2 + requesting all changes + abort: remote error: + incompatible Mercurial client; bundle2 required + (see https://www.mercurial-scm.org/wiki/IncompatibleClient) + [255] + $ killdaemons.py + +Verify the global server.bundle1 option works + + $ cat > .hg/hgrc << EOF + > [server] + > bundle1 = false + > EOF + $ hg serve -p $HGPORT -d --pid-file=hg.pid + $ cat hg.pid >> $DAEMON_PIDS + $ hg --config experimental.bundle2-exp=false clone http://localhost:$HGPORT not-bundle2 + requesting all changes + abort: remote error: + incompatible Mercurial client; bundle2 required + (see https://www.mercurial-scm.org/wiki/IncompatibleClient) + [255] + $ killdaemons.py + +Verify bundle1 pushes can be disabled + + $ cat > .hg/hgrc << EOF + > [server] + > bundle1.push = false + > [web] + > allow_push = * + > push_ssl = false + > EOF + + $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log + $ cat hg.pid >> $DAEMON_PIDS + $ cd .. + + $ hg clone http://localhost:$HGPORT bundle2-only + requesting all changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cd bundle2-only + $ echo commit > foo + $ hg commit -m commit + $ hg --config experimental.bundle2-exp=false push + pushing to http://localhost:$HGPORT/ + searching for changes + abort: remote error: + incompatible Mercurial client; bundle2 required + (see https://www.mercurial-scm.org/wiki/IncompatibleClient) + [255] + + $ hg push + pushing to http://localhost:$HGPORT/ + searching for changes + remote: adding changesets + remote: adding manifests + remote: adding file changes + remote: added 1 changesets with 1 changes to 1 files