D2019: wireprotoserver: move protocol parsing and dispatch out of hgweb
indygreg (Gregory Szorc)
phabricator at mercurial-scm.org
Tue Feb 6 16:04:53 EST 2018
indygreg updated this revision to Diff 5259.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D2019?vs=5173&id=5259
REVISION DETAIL
https://phab.mercurial-scm.org/D2019
AFFECTED FILES
mercurial/hgweb/hgweb_mod.py
mercurial/wireprotoserver.py
CHANGE DETAILS
diff --git a/mercurial/wireprotoserver.py b/mercurial/wireprotoserver.py
--- a/mercurial/wireprotoserver.py
+++ b/mercurial/wireprotoserver.py
@@ -202,9 +202,43 @@
def iscmd(cmd):
return cmd in wireproto.commands
-def callhttp(repo, req, cmd):
+def parsehttprequest(repo, req, query):
+ """Parse the HTTP request for a wire protocol request.
+
+ If the current request appears to be a wire protocol request, this
+ function returns a dict with details about that request, including
+ an ``abstractprotocolserver`` instance suitable for handling the
+ request. Otherwise, ``None`` is returned.
+
+ ``req`` is a ``wsgirequest`` instance.
+ """
+ # HTTP version 1 wire protocol requests are denoted by a "cmd" query
+ # string parameter. If it isn't present, this isn't a wire protocol
+ # request.
+ if r'cmd' not in req.form:
+ return None
+
+ cmd = pycompat.sysbytes(req.form[r'cmd'][0])
+
+ # The "cmd" request parameter is used by both the wire protocol and hgweb.
+ # While not all wire protocol commands are available for all transports,
+ # if we see a "cmd" value that resembles a known wire protocol command, we
+ # route it to a protocol handler. This is better than routing possible
+ # wire protocol requests to hgweb because it prevents hgweb from using
+ # known wire protocol commands and it is less confusing for machine
+ # clients.
+ if cmd not in wireproto.commands:
+ return None
+
proto = webproto(req, repo.ui)
+ return {
+ 'cmd': cmd,
+ 'proto': proto,
+ 'dispatch': lambda: _callhttp(repo, req, proto, cmd),
+ }
+
+def _callhttp(repo, req, proto, cmd):
def genversion2(gen, engine, engineopts):
# application/mercurial-0.2 always sends a payload header
# identifying the compression engine.
diff --git a/mercurial/hgweb/hgweb_mod.py b/mercurial/hgweb/hgweb_mod.py
--- a/mercurial/hgweb/hgweb_mod.py
+++ b/mercurial/hgweb/hgweb_mod.py
@@ -357,26 +357,18 @@
query = req.env[r'QUERY_STRING'].partition(r'&')[0]
query = query.partition(r';')[0]
- # The ``cmd`` request parameter is used by both the wire protocol
- # and hgweb. We route all known wire protocol commands to the
- # wire protocol handler, even if the command isn't available for
- # this transport. That's better for machine clients in the case
- # of an errant request to an unavailable protocol command. And it
- # prevents hgweb from accidentally using ``cmd`` values used by
- # the wire protocol.
+ # Route it to a wire protocol handler if it looks like a wire protocol
+ # request.
+ protohandler = wireprotoserver.parsehttprequest(rctx.repo, req, query)
- # process this if it's a protocol request
- # protocol bits don't need to create any URLs
- # and the clients always use the old URL structure
-
- cmd = pycompat.sysbytes(req.form.get(r'cmd', [r''])[0])
- if wireprotoserver.iscmd(cmd):
+ if protohandler:
+ cmd = protohandler['cmd']
try:
if query:
raise ErrorResponse(HTTP_NOT_FOUND)
if cmd in perms:
self.check_perm(rctx, req, perms[cmd])
- return wireprotoserver.callhttp(rctx.repo, req, cmd)
+ return protohandler['dispatch']()
except ErrorResponse as inst:
# A client that sends unbundle without 100-continue will
# break if we respond early.
@@ -425,6 +417,8 @@
if fn.endswith(ext):
req.form['node'] = [fn[:-len(ext)]]
req.form['type'] = [type_]
+ else:
+ cmd = pycompat.sysbytes(req.form.get(r'cmd', [r''])[0])
# process the web interface request
To: indygreg, #hg-reviewers
Cc: mercurial-devel
More information about the Mercurial-devel
mailing list