diff -r 7283719e2bfd -r 35b516f800e0 mercurial/wireproto.py --- a/mercurial/wireproto.py Sat Dec 24 13:51:12 2016 -0700 +++ b/mercurial/wireproto.py Sat Dec 24 15:21:46 2016 -0700 @@ -607,6 +607,55 @@ return ui.configbool('server', 'bundle1', True) +def supportedcompengines(ui, proto, role): + """Obtain the list of supported compression engines for a request.""" + assert role in (util.CLIENTROLE, util.SERVERROLE) + + compengines = util.compengines.supportedwireengines(role) + + # Allow config to override default list and ordering. + if role == util.SERVERROLE: + configengines = ui.configlist('server', 'compressionengines') + config = 'server.compressionengines' + else: + # This is currently implemented mainly to facilitate testing. In most + # cases, the server should be in charge of choosing a compression engine + # because a server has the most to lose from a sub-optimal choice. (e.g. + # CPU DoS due to an expensive engine or a network DoS due to poor + # compression ratio). + configengines = ui.configlist('experimental', + 'clientcompressionengines') + config = 'experimental.clientcompressionengines' + + # No explicit config. Filter out the ones that aren't supposed to be + # advertised and return default ordering. + if not configengines: + attr = 'serverpriority' if role == util.SERVERROLE else 'clientpriority' + return [e for e in compengines + if getattr(e.wireprotosupport(), attr) > 0] + + # If compression engines are listed in the config, assume there is a good + # reason for it (like server operators wanting to achieve specific + # performance characteristics). So fail fast if the config references + # unusable compression engines. + validnames = set(e.name() for e in compengines) + invalidnames = set(e for e in configengines if e not in validnames) + if invalidnames: + raise error.Abort(_('invalid compression engine defined in %s: %s') % + (config, ', '.join(sorted(invalidnames)))) + + compengines = [e for e in compengines if e.name() in configengines] + compengines = sorted(compengines, + key=lambda e: configengines.index(e.name())) + + if not compengines: + raise error.Abort(_('%s config option does not specify any known ' + 'compression engines') % config, + hint=_('usable compression engines: %s') % + ', '.sorted(validnames)) + + return compengines + # list of commands commands = {} @@ -723,6 +772,16 @@ if repo.ui.configbool('experimental', 'httppostargs', False): caps.append('httppostargs') + # FUTURE advertise 0.2rx once support is implemented + # FUTURE advertise minrx and mintx after consulting config option + caps.append('httpmediatype=0.1rx,0.1tx,0.2tx') + + compengines = supportedcompengines(repo.ui, proto, util.SERVERROLE) + if compengines: + comptypes = ','.join(urlreq.quote(e.wireprotosupport().name) + for e in compengines) + caps.append('compression=%s' % comptypes) + return caps # If you are writing an extension and consider wrapping this function. Wrap