mercurial/wireprotoserver.py
changeset 36801 66de4555cefd
parent 36800 0b18604db95e
child 36804 b9b968e21f78
equal deleted inserted replaced
36800:0b18604db95e 36801:66de4555cefd
    52         i += 1
    52         i += 1
    53 
    53 
    54     return ''.join(chunks)
    54     return ''.join(chunks)
    55 
    55 
    56 class httpv1protocolhandler(wireprototypes.baseprotocolhandler):
    56 class httpv1protocolhandler(wireprototypes.baseprotocolhandler):
    57     def __init__(self, req, ui):
    57     def __init__(self, req, ui, checkperm):
    58         self._req = req
    58         self._req = req
    59         self._ui = ui
    59         self._ui = ui
       
    60         self._checkperm = checkperm
    60 
    61 
    61     @property
    62     @property
    62     def name(self):
    63     def name(self):
    63         return 'http-v1'
    64         return 'http-v1'
    64 
    65 
   137                                  for e in compengines)
   138                                  for e in compengines)
   138             caps.append('compression=%s' % comptypes)
   139             caps.append('compression=%s' % comptypes)
   139 
   140 
   140         return caps
   141         return caps
   141 
   142 
       
   143     def checkperm(self, perm):
       
   144         return self._checkperm(perm)
       
   145 
   142 # This method exists mostly so that extensions like remotefilelog can
   146 # This method exists mostly so that extensions like remotefilelog can
   143 # disable a kludgey legacy method only over http. As of early 2018,
   147 # disable a kludgey legacy method only over http. As of early 2018,
   144 # there are no other known users, so with any luck we can discard this
   148 # there are no other known users, so with any luck we can discard this
   145 # hook if remotefilelog becomes a first-party extension.
   149 # hook if remotefilelog becomes a first-party extension.
   146 def iscmd(cmd):
   150 def iscmd(cmd):
   147     return cmd in wireproto.commands
   151     return cmd in wireproto.commands
   148 
   152 
   149 def parsehttprequest(repo, req, query):
   153 def parsehttprequest(rctx, req, query, checkperm):
   150     """Parse the HTTP request for a wire protocol request.
   154     """Parse the HTTP request for a wire protocol request.
   151 
   155 
   152     If the current request appears to be a wire protocol request, this
   156     If the current request appears to be a wire protocol request, this
   153     function returns a dict with details about that request, including
   157     function returns a dict with details about that request, including
   154     an ``abstractprotocolserver`` instance suitable for handling the
   158     an ``abstractprotocolserver`` instance suitable for handling the
   155     request. Otherwise, ``None`` is returned.
   159     request. Otherwise, ``None`` is returned.
   156 
   160 
   157     ``req`` is a ``wsgirequest`` instance.
   161     ``req`` is a ``wsgirequest`` instance.
   158     """
   162     """
       
   163     repo = rctx.repo
       
   164 
   159     # HTTP version 1 wire protocol requests are denoted by a "cmd" query
   165     # HTTP version 1 wire protocol requests are denoted by a "cmd" query
   160     # string parameter. If it isn't present, this isn't a wire protocol
   166     # string parameter. If it isn't present, this isn't a wire protocol
   161     # request.
   167     # request.
   162     if 'cmd' not in req.form:
   168     if 'cmd' not in req.form:
   163         return None
   169         return None
   172     # known wire protocol commands and it is less confusing for machine
   178     # known wire protocol commands and it is less confusing for machine
   173     # clients.
   179     # clients.
   174     if not iscmd(cmd):
   180     if not iscmd(cmd):
   175         return None
   181         return None
   176 
   182 
   177     proto = httpv1protocolhandler(req, repo.ui)
   183     proto = httpv1protocolhandler(req, repo.ui,
       
   184                                   lambda perm: checkperm(rctx, req, perm))
   178 
   185 
   179     return {
   186     return {
   180         'cmd': cmd,
   187         'cmd': cmd,
   181         'proto': proto,
   188         'proto': proto,
   182         'dispatch': lambda checkperm: _callhttp(repo, req, proto, cmd,
   189         'dispatch': lambda: _callhttp(repo, req, proto, cmd),
   183                                                 checkperm),
       
   184         'handleerror': lambda ex: _handlehttperror(ex, req, cmd),
   190         'handleerror': lambda ex: _handlehttperror(ex, req, cmd),
   185     }
   191     }
   186 
   192 
   187 def _httpresponsetype(ui, req, prefer_uncompressed):
   193 def _httpresponsetype(ui, req, prefer_uncompressed):
   188     """Determine the appropriate response type and compression settings.
   194     """Determine the appropriate response type and compression settings.
   222     # setting a very high compression level could lead to flooding
   228     # setting a very high compression level could lead to flooding
   223     # the server's network or CPU.
   229     # the server's network or CPU.
   224     opts = {'level': ui.configint('server', 'zliblevel')}
   230     opts = {'level': ui.configint('server', 'zliblevel')}
   225     return HGTYPE, util.compengines['zlib'], opts
   231     return HGTYPE, util.compengines['zlib'], opts
   226 
   232 
   227 def _callhttp(repo, req, proto, cmd, checkperm):
   233 def _callhttp(repo, req, proto, cmd):
   228     def genversion2(gen, engine, engineopts):
   234     def genversion2(gen, engine, engineopts):
   229         # application/mercurial-0.2 always sends a payload header
   235         # application/mercurial-0.2 always sends a payload header
   230         # identifying the compression engine.
   236         # identifying the compression engine.
   231         name = engine.wireprotosupport().name
   237         name = engine.wireprotosupport().name
   232         assert 0 < len(name) < 256
   238         assert 0 < len(name) < 256
   240         req.respond(HTTP_OK, HGERRTYPE,
   246         req.respond(HTTP_OK, HGERRTYPE,
   241                     body=_('requested wire protocol command is not available '
   247                     body=_('requested wire protocol command is not available '
   242                            'over HTTP'))
   248                            'over HTTP'))
   243         return []
   249         return []
   244 
   250 
   245     checkperm(wireproto.commands[cmd].permission)
   251     proto.checkperm(wireproto.commands[cmd].permission)
   246 
   252 
   247     rsp = wireproto.dispatch(repo, proto, cmd)
   253     rsp = wireproto.dispatch(repo, proto, cmd)
   248 
   254 
   249     if isinstance(rsp, bytes):
   255     if isinstance(rsp, bytes):
   250         req.respond(HTTP_OK, HGTYPE, body=rsp)
   256         req.respond(HTTP_OK, HGTYPE, body=rsp)
   390         return 'remote:ssh:' + client
   396         return 'remote:ssh:' + client
   391 
   397 
   392     def addcapabilities(self, repo, caps):
   398     def addcapabilities(self, repo, caps):
   393         return caps
   399         return caps
   394 
   400 
       
   401     def checkperm(self, perm):
       
   402         pass
       
   403 
   395 class sshv2protocolhandler(sshv1protocolhandler):
   404 class sshv2protocolhandler(sshv1protocolhandler):
   396     """Protocol handler for version 2 of the SSH protocol."""
   405     """Protocol handler for version 2 of the SSH protocol."""
   397 
   406 
   398     @property
   407     @property
   399     def name(self):
   408     def name(self):