mercurial/wireprotoserver.py
changeset 36812 158d4ecc03c8
parent 36810 886fba199022
child 36813 5a3c83412f79
equal deleted inserted replaced
36811:cfb9ef24968c 36812:158d4ecc03c8
   148 # 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
   149 # hook if remotefilelog becomes a first-party extension.
   149 # hook if remotefilelog becomes a first-party extension.
   150 def iscmd(cmd):
   150 def iscmd(cmd):
   151     return cmd in wireproto.commands
   151     return cmd in wireproto.commands
   152 
   152 
   153 def parsehttprequest(rctx, wsgireq, req, checkperm):
   153 def handlewsgirequest(rctx, wsgireq, req, checkperm):
   154     """Parse the HTTP request for a wire protocol request.
   154     """Possibly process a wire protocol request.
   155 
   155 
   156     If the current request appears to be a wire protocol request, this
   156     If the current request is a wire protocol request, the request is
   157     function returns a dict with details about that request, including
   157     processed by this function.
   158     an ``abstractprotocolserver`` instance suitable for handling the
       
   159     request. Otherwise, ``None`` is returned.
       
   160 
   158 
   161     ``wsgireq`` is a ``wsgirequest`` instance.
   159     ``wsgireq`` is a ``wsgirequest`` instance.
   162     ``req`` is a ``parsedrequest`` instance.
   160     ``req`` is a ``parsedrequest`` instance.
       
   161 
       
   162     Returns a 2-tuple of (bool, response) where the 1st element indicates
       
   163     whether the request was handled and the 2nd element is a return
       
   164     value for a WSGI application (often a generator of bytes).
   163     """
   165     """
       
   166     # Avoid cycle involving hg module.
       
   167     from .hgweb import common as hgwebcommon
       
   168 
   164     repo = rctx.repo
   169     repo = rctx.repo
   165 
   170 
   166     # HTTP version 1 wire protocol requests are denoted by a "cmd" query
   171     # HTTP version 1 wire protocol requests are denoted by a "cmd" query
   167     # string parameter. If it isn't present, this isn't a wire protocol
   172     # string parameter. If it isn't present, this isn't a wire protocol
   168     # request.
   173     # request.
   169     if 'cmd' not in req.querystringdict:
   174     if 'cmd' not in req.querystringdict:
   170         return None
   175         return False, None
   171 
   176 
   172     cmd = req.querystringdict['cmd'][0]
   177     cmd = req.querystringdict['cmd'][0]
   173 
   178 
   174     # The "cmd" request parameter is used by both the wire protocol and hgweb.
   179     # The "cmd" request parameter is used by both the wire protocol and hgweb.
   175     # While not all wire protocol commands are available for all transports,
   180     # While not all wire protocol commands are available for all transports,
   177     # route it to a protocol handler. This is better than routing possible
   182     # route it to a protocol handler. This is better than routing possible
   178     # wire protocol requests to hgweb because it prevents hgweb from using
   183     # wire protocol requests to hgweb because it prevents hgweb from using
   179     # known wire protocol commands and it is less confusing for machine
   184     # known wire protocol commands and it is less confusing for machine
   180     # clients.
   185     # clients.
   181     if not iscmd(cmd):
   186     if not iscmd(cmd):
   182         return None
   187         return False, None
       
   188 
       
   189     # The "cmd" query string argument is only valid on the root path of the
       
   190     # repo. e.g. ``/?cmd=foo``, ``/repo?cmd=foo``. URL paths within the repo
       
   191     # like ``/blah?cmd=foo`` are not allowed. So don't recognize the request
       
   192     # in this case. We send an HTTP 404 for backwards compatibility reasons.
       
   193     if req.dispatchpath:
       
   194         res = _handlehttperror(
       
   195             hgwebcommon.ErrorResponse(hgwebcommon.HTTP_NOT_FOUND), wsgireq,
       
   196             cmd)
       
   197 
       
   198         return True, res
   183 
   199 
   184     proto = httpv1protocolhandler(wsgireq, repo.ui,
   200     proto = httpv1protocolhandler(wsgireq, repo.ui,
   185                                   lambda perm: checkperm(rctx, wsgireq, perm))
   201                                   lambda perm: checkperm(rctx, wsgireq, perm))
   186 
   202 
   187     return {
   203     # The permissions checker should be the only thing that can raise an
   188         'cmd': cmd,
   204     # ErrorResponse. It is kind of a layer violation to catch an hgweb
   189         'proto': proto,
   205     # exception here. So consider refactoring into a exception type that
   190         'dispatch': lambda: _callhttp(repo, wsgireq, proto, cmd),
   206     # is associated with the wire protocol.
   191         'handleerror': lambda ex: _handlehttperror(ex, wsgireq, cmd),
   207     try:
   192     }
   208         res = _callhttp(repo, wsgireq, proto, cmd)
       
   209     except hgwebcommon.ErrorResponse as e:
       
   210         res = _handlehttperror(e, wsgireq, cmd)
       
   211 
       
   212     return True, res
   193 
   213 
   194 def _httpresponsetype(ui, wsgireq, prefer_uncompressed):
   214 def _httpresponsetype(ui, wsgireq, prefer_uncompressed):
   195     """Determine the appropriate response type and compression settings.
   215     """Determine the appropriate response type and compression settings.
   196 
   216 
   197     Returns a tuple of (mediatype, compengine, engineopts).
   217     Returns a tuple of (mediatype, compengine, engineopts).