# HG changeset patch # User Angel Ezquerra # Date 1360493525 -3600 # Node ID bb38f4f78104f16ba3538df3b8cb3465755e5f57 # Parent dcb6a99e82ff4569c059224b26c13bd189e8691a 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 ('glob', 'relglob', 'path', 'relpath', 're', 'relre' nor 'set'). The server will reject those with a 403 HTTP error response. Note that this is a first step to add support for downloading directories from the web interface. A following patch will modify the archiveentry map entry on the different templates so that it adds the current folder path to the archive links. diff -r dcb6a99e82ff -r bb38f4f78104 mercurial/hgweb/webcommands.py --- a/mercurial/hgweb/webcommands.py Wed Feb 06 10:06:45 2013 +0100 +++ b/mercurial/hgweb/webcommands.py Sun Feb 10 11:52:05 2013 +0100 @@ -816,6 +816,19 @@ 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) + if file: + file = file[0] + patandfile = file.split(':') + if len(patandfile) > 1 and patandfile[0].lower() in ('glob', 'relglob', + 'path', 'relpath', 're', 'relre', 'set'): + msg = 'Archive pattern not allowed: %s' % file + raise ErrorResponse(HTTP_FORBIDDEN, msg) + pats = ['path:' + file] + mimetype, artype, extension, encoding = web.archive_specs[type_] headers = [ ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension)) @@ -825,9 +838,9 @@ req.headers.extend(headers) req.respond(HTTP_OK, mimetype) - ctx = webutil.changectx(web.repo, req) + matchfn = scmutil.match(ctx, pats, default='path') archival.archive(web.repo, req, cnode, artype, prefix=name, - matchfn=scmutil.match(ctx, []), + matchfn=matchfn, subrepos=web.configbool("web", "archivesubrepos")) return [] diff -r dcb6a99e82ff -r bb38f4f78104 tests/test-archive.t --- a/tests/test-archive.t Wed Feb 06 10:06:45 2013 +0100 +++ b/tests/test-archive.t Sun Feb 10 11:52:05 2013 +0100 @@ -101,6 +101,18 @@ testing: test-archive-2c0277f05ed4/foo OK No errors detected in compressed data of archive.zip. +test that we can download single directories and files + + $ python getarchive.py "$TIP" gz baz | gunzip | tar tf - 2>/dev/null + test-archive-2c0277f05ed4/baz/bletch + $ python getarchive.py "$TIP" gz foo | gunzip | tar tf - 2>/dev/null + test-archive-2c0277f05ed4/foo + +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 $ hg archive -t tar test.tar