[PATCH 2 of 2 V5] hgweb: teach archive how to download a specific directory or file

Angel Ezquerra angel.ezquerra at gmail.com
Sun Feb 17 17:14:01 CST 2013


# HG changeset patch
# User Angel Ezquerra <angel.ezquerra at gmail.com>
# Date 1360493525 -3600
# Node ID 45216cdf25a89a6392901a10fde16b7f96307cc5
# Parent  2f7b559540108a021cba31c0c7affa011ef119cc
hgweb: teach archive how to download a specific directory or file

The archive web command now takes into account the "file" request entry, if one
is provided.

The provided "file" is processed as a "path" corresponding to a directory or
file that will be downloaded.

With this change hgweb can to process requests such as:

    http://mercurial.selenic.com/hg/archive/tip.zip/mercurial/templates

This will download all files on the mercurial/templates directory as a zip file.
It is not possible to specify file patterns. Those will be rejected with a 403
reply fromthe server.

Note that this is a first step to add support for downloading directories from
the web interface. Currently the only way to use this feature is by manually
constructing the URL that you want to download. We will have to modify the
archiveentry map entry on the different templates so that it adds the current
folder path to the archive links.

This revision also adds a two tests for this feature to test-archive.t. The
first tests the selective archive feature and the second tests that the server
rejects patterns.

diff --git a/mercurial/hgweb/webcommands.py b/mercurial/hgweb/webcommands.py
--- a/mercurial/hgweb/webcommands.py
+++ b/mercurial/hgweb/webcommands.py
@@ -816,6 +816,17 @@
     if cnode == key or key == 'tip':
         arch_version = short(cnode)
     name = "%s-%s" % (reponame, arch_version)
+
+    ctx = webutil.changectx(web.repo, req)
+    pats = []
+    file = req.form.get('file', None)
+    defaultpat = 'path'
+    if file:
+        pats = [req.form['file'][0]]
+        if ':' in pats[0]:
+            msg = 'Archive pattern not allowed: %s' % pats[0]
+            raise ErrorResponse(HTTP_FORBIDDEN, msg)
+
     mimetype, artype, extension, encoding = web.archive_specs[type_]
     headers = [
         ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
@@ -825,9 +836,9 @@
     req.headers.extend(headers)
     req.respond(HTTP_OK, mimetype)
 
-    ctx = webutil.changectx(web.repo, req)
+    matchfn = scmutil.match(ctx, pats, default=defaultpat)
     archival.archive(web.repo, req, cnode, artype, prefix=name,
-                     matchfn=scmutil.match(ctx, []),
+                     matchfn=matchfn,
                      subrepos=web.configbool("web", "archivesubrepos"))
     return []
 
diff --git a/tests/test-archive.t b/tests/test-archive.t
--- a/tests/test-archive.t
+++ b/tests/test-archive.t
@@ -100,6 +100,13 @@
       testing: test-archive-2c0277f05ed4/baz/bletch   OK
       testing: test-archive-2c0277f05ed4/foo   OK
   No errors detected in compressed data of archive.zip.
+  $ python getarchive.py "$TIP" gz baz | gunzip | tar tf - 2>/dev/null
+  test-archive-2c0277f05ed4/baz/bletch
+
+test that we reject unsafe patterns
+
+  $ python getarchive.py "$TIP" gz relre:baz
+  HTTP Error 403: Archive pattern not allowed: relre:baz
 
   $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
 


More information about the Mercurial-devel mailing list