diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -2915,9 +2915,12 @@ raise error.Abort(_('--peer %s not supported with HTTP peers') % opts['peer']) else: + url, caps = httppeer.performhandshake(ui, url, opener, + httppeer.urlreq.request) + peer = httppeer.httppeer(ui, path, url, opener, - requestbuilder=httppeer.urlreq.request) - peer._fetchcaps() + httppeer.urlreq.request, + caps) # We /could/ populate stdin/stdout with sock.makefile()... else: diff --git a/mercurial/httppeer.py b/mercurial/httppeer.py --- a/mercurial/httppeer.py +++ b/mercurial/httppeer.py @@ -366,11 +366,11 @@ return respurl, resp class httppeer(wireproto.wirepeer): - def __init__(self, ui, path, url, opener, requestbuilder): + def __init__(self, ui, path, url, opener, requestbuilder, caps): self.ui = ui self._path = path self._url = url - self._caps = None + self._caps = caps self._urlopener = opener self._requestbuilder = requestbuilder @@ -401,18 +401,12 @@ # Begin of ipeercommands interface. def capabilities(self): - # self._fetchcaps() should have been called as part of peer - # handshake. So self._caps should always be set. - assert self._caps is not None return self._caps # End of ipeercommands interface. # look up capabilities only when needed - def _fetchcaps(self): - self._caps = set(self._call('capabilities').split()) - def _callstream(self, cmd, _compressible=False, **args): args = pycompat.byteskwargs(args) @@ -603,6 +597,29 @@ return results +def performhandshake(ui, url, opener, requestbuilder): + # The handshake is a request to the capabilities command. + + caps = None + def capable(x): + raise error.ProgrammingError('should not be called') + + req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps, + capable, url, 'capabilities', + {}) + + resp = sendrequest(ui, opener, req) + + respurl, resp = parsev1commandresponse(ui, url, requrl, qs, resp, + compressible=False) + + try: + rawcaps = resp.read() + finally: + resp.close() + + return respurl, set(rawcaps.split()) + def makepeer(ui, path, requestbuilder=urlreq.request): """Construct an appropriate HTTP peer instance. @@ -620,7 +637,9 @@ opener = urlmod.opener(ui, authinfo) - return httppeer(ui, path, url, opener, requestbuilder) + respurl, caps = performhandshake(ui, url, opener, requestbuilder) + + return httppeer(ui, path, respurl, opener, requestbuilder, caps) def instance(ui, path, create): if create: @@ -631,7 +650,6 @@ 'is not installed')) inst = makepeer(ui, path) - inst._fetchcaps() return inst except error.RepoError as httpexception: diff --git a/tests/test-check-interfaces.py b/tests/test-check-interfaces.py --- a/tests/test-check-interfaces.py +++ b/tests/test-check-interfaces.py @@ -67,10 +67,11 @@ class dummyopener(object): handlers = [] -# Facilitates testing sshpeer without requiring an SSH server. +# Facilitates testing sshpeer without requiring a server. class badpeer(httppeer.httppeer): def __init__(self): - super(badpeer, self).__init__(None, None, None, dummyopener(), None) + super(badpeer, self).__init__(None, None, None, dummyopener(), None, + None) self.badattribute = True def badmethod(self): @@ -89,7 +90,7 @@ ziverify.verifyClass(repository.ipeerbaselegacycommands, httppeer.httppeer) - checkzobject(httppeer.httppeer(None, None, None, dummyopener(), None)) + checkzobject(httppeer.httppeer(None, None, None, dummyopener(), None, None)) ziverify.verifyClass(repository.ipeerbase, localrepo.localpeer)