Mercurial > public > mercurial-scm > hg
comparison mercurial/httppeer.py @ 37552:8b8a845c85fc
httppeer: perform capabilities request in makepeer()
Previously, we constructed an httppeer then always ran _fetchcaps()
to issue the capabilities command.
We want to issue the capabilities command before constructing a
peer instance so we can construct an appropriate peer instance
depending on the capabilities result.
With the code for making and sending requests moved out of httppeer,
it is now possible to send command requests without an httppeer.
This commit creates a new function for making the capabilities
request and calls it as part of makepeer().
This code should be functionality equivalent to what existed before.
Differential Revision: https://phab.mercurial-scm.org/D3237
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Tue, 10 Apr 2018 13:11:40 -0700 |
parents | 946eb204ba67 |
children | 6b08cf6b900f |
comparison
equal
deleted
inserted
replaced
37551:946eb204ba67 | 37552:8b8a845c85fc |
---|---|
364 resp = util.compengines['zlib'].decompressorreader(resp) | 364 resp = util.compengines['zlib'].decompressorreader(resp) |
365 | 365 |
366 return respurl, resp | 366 return respurl, resp |
367 | 367 |
368 class httppeer(wireproto.wirepeer): | 368 class httppeer(wireproto.wirepeer): |
369 def __init__(self, ui, path, url, opener, requestbuilder): | 369 def __init__(self, ui, path, url, opener, requestbuilder, caps): |
370 self.ui = ui | 370 self.ui = ui |
371 self._path = path | 371 self._path = path |
372 self._url = url | 372 self._url = url |
373 self._caps = None | 373 self._caps = caps |
374 self._urlopener = opener | 374 self._urlopener = opener |
375 self._requestbuilder = requestbuilder | 375 self._requestbuilder = requestbuilder |
376 | 376 |
377 def __del__(self): | 377 def __del__(self): |
378 for h in self._urlopener.handlers: | 378 for h in self._urlopener.handlers: |
399 # End of ipeerconnection interface. | 399 # End of ipeerconnection interface. |
400 | 400 |
401 # Begin of ipeercommands interface. | 401 # Begin of ipeercommands interface. |
402 | 402 |
403 def capabilities(self): | 403 def capabilities(self): |
404 # self._fetchcaps() should have been called as part of peer | |
405 # handshake. So self._caps should always be set. | |
406 assert self._caps is not None | |
407 return self._caps | 404 return self._caps |
408 | 405 |
409 # End of ipeercommands interface. | 406 # End of ipeercommands interface. |
410 | 407 |
411 # look up capabilities only when needed | 408 # look up capabilities only when needed |
412 | |
413 def _fetchcaps(self): | |
414 self._caps = set(self._call('capabilities').split()) | |
415 | 409 |
416 def _callstream(self, cmd, _compressible=False, **args): | 410 def _callstream(self, cmd, _compressible=False, **args): |
417 args = pycompat.byteskwargs(args) | 411 args = pycompat.byteskwargs(args) |
418 | 412 |
419 req, cu, qs = makev1commandrequest(self.ui, self._requestbuilder, | 413 req, cu, qs = makev1commandrequest(self.ui, self._requestbuilder, |
601 else: | 595 else: |
602 error.ProgrammingError('unhandled action: %s' % action) | 596 error.ProgrammingError('unhandled action: %s' % action) |
603 | 597 |
604 return results | 598 return results |
605 | 599 |
600 def performhandshake(ui, url, opener, requestbuilder): | |
601 # The handshake is a request to the capabilities command. | |
602 | |
603 caps = None | |
604 def capable(x): | |
605 raise error.ProgrammingError('should not be called') | |
606 | |
607 req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps, | |
608 capable, url, 'capabilities', | |
609 {}) | |
610 | |
611 resp = sendrequest(ui, opener, req) | |
612 | |
613 respurl, resp = parsev1commandresponse(ui, url, requrl, qs, resp, | |
614 compressible=False) | |
615 | |
616 try: | |
617 rawcaps = resp.read() | |
618 finally: | |
619 resp.close() | |
620 | |
621 return respurl, set(rawcaps.split()) | |
622 | |
606 def makepeer(ui, path, requestbuilder=urlreq.request): | 623 def makepeer(ui, path, requestbuilder=urlreq.request): |
607 """Construct an appropriate HTTP peer instance. | 624 """Construct an appropriate HTTP peer instance. |
608 | 625 |
609 ``requestbuilder`` is the type used for constructing HTTP requests. | 626 ``requestbuilder`` is the type used for constructing HTTP requests. |
610 It exists as an argument so extensions can override the default. | 627 It exists as an argument so extensions can override the default. |
618 url, authinfo = u.authinfo() | 635 url, authinfo = u.authinfo() |
619 ui.debug('using %s\n' % url) | 636 ui.debug('using %s\n' % url) |
620 | 637 |
621 opener = urlmod.opener(ui, authinfo) | 638 opener = urlmod.opener(ui, authinfo) |
622 | 639 |
623 return httppeer(ui, path, url, opener, requestbuilder) | 640 respurl, caps = performhandshake(ui, url, opener, requestbuilder) |
641 | |
642 return httppeer(ui, path, respurl, opener, requestbuilder, caps) | |
624 | 643 |
625 def instance(ui, path, create): | 644 def instance(ui, path, create): |
626 if create: | 645 if create: |
627 raise error.Abort(_('cannot create new http repository')) | 646 raise error.Abort(_('cannot create new http repository')) |
628 try: | 647 try: |
629 if path.startswith('https:') and not urlmod.has_https: | 648 if path.startswith('https:') and not urlmod.has_https: |
630 raise error.Abort(_('Python support for SSL and HTTPS ' | 649 raise error.Abort(_('Python support for SSL and HTTPS ' |
631 'is not installed')) | 650 'is not installed')) |
632 | 651 |
633 inst = makepeer(ui, path) | 652 inst = makepeer(ui, path) |
634 inst._fetchcaps() | |
635 | 653 |
636 return inst | 654 return inst |
637 except error.RepoError as httpexception: | 655 except error.RepoError as httpexception: |
638 try: | 656 try: |
639 r = statichttprepo.instance(ui, "static-" + path, create) | 657 r = statichttprepo.instance(ui, "static-" + path, create) |