[PATCH 2 of 2 V2] hgweb: add a hook for processing LFS file transfer requests

Matt Harbison mharbison72 at gmail.com
Wed Mar 7 23:49:01 EST 2018


# HG changeset patch
# User Matt Harbison <matt_harbison at yahoo.com>
# Date 1519275362 18000
#      Wed Feb 21 23:56:02 2018 -0500
# Node ID 5544688dec388a7c8a988c074aab659f059f549f
# Parent  89382cb20bb19e089513b2ce69ef8acfa1f523fd
hgweb: add a hook for processing LFS file transfer requests

As part of this, the PUT request needs to be handled to upload files.  Unlike
the requests to the Batch API, this URI is internally controlled, and provided
to the client in the Batch API.  So without any interoperability concerns, the
URI starts with '/.hg', and reflects where the files are actually stored.

The permission check is deferred to the processing function, because this
request is used for both uploads and downloads.

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
@@ -96,6 +96,15 @@
     """
     raise ErrorResponse(HTTP_NOT_FOUND)
 
+def _processlfstransfer(repo, req):
+    """A hook for the LFS extension to wrap that handles file transfer requests.
+
+    The caller MUST call ``req.checkperm()`` with 'push' or 'pull' after it
+    determines whether this is an upload or a download, prior to accessing any
+    repository data.
+    """
+    raise ErrorResponse(HTTP_NOT_FOUND)
+
 class requestcontext(object):
     """Holds state/context for an individual request.
 
@@ -382,14 +391,20 @@
             except ErrorResponse as inst:
                 return protohandler['handleerror'](inst)
 
-        # Route LFS Batch API requests to the appropriate handler
+        # Route LFS Batch API and transfer requests to the appropriate handler
 
         if req.env.get(r'HTTP_USER_AGENT', r'').startswith(r'git-lfs/'):
             try:
-                path = req.env.get(r'PATH_INFO')
+                path = req.env.get(r'PATH_INFO', '')
                 if path == '/.git/info/lfs/objects/batch':
                     self.check_perm(rctx, req, None)
                     return _processlfsbatchreq(rctx.repo, req)
+                elif path.startswith('/.hg/store/lfs/objects'):
+                    # NB: This function is responsible for doing the appropriate
+                    # permission checks after determining if this is an upload
+                    # or a download.
+                    req.checkperm = lambda op: self.check_perm(rctx, req, op)
+                    return _processlfstransfer(rctx.repo, req)
                 else:
                     raise ErrorResponse(HTTP_NOT_FOUND)
             except ErrorResponse as inst:
diff --git a/mercurial/hgweb/server.py b/mercurial/hgweb/server.py
--- a/mercurial/hgweb/server.py
+++ b/mercurial/hgweb/server.py
@@ -111,6 +111,9 @@
             self.log_error(r"Exception happened during processing "
                            r"request '%s':%s%s", self.path, newline, tb)
 
+    def do_PUT(self):
+        self.do_POST()
+
     def do_GET(self):
         self.do_POST()
 


More information about the Mercurial-devel mailing list