mercurial/httppeer.py
changeset 37552 8b8a845c85fc
parent 37551 946eb204ba67
child 37553 6b08cf6b900f
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)