Mercurial > public > mercurial-scm > hg
diff mercurial/hgweb/webcommands.py @ 51834:3b8d92f71d92
archive: defer opening the output until a file is matched
Before, if no file is matched, an error is thrown, but the archive is
created anyway. When using hgweb, an error 500 is returned as the
response body already exists when the error is seen.
Afterwards, the archive is created before the first match is emitted.
If no match is found, no archive is created. This is more consistent
behavior as an empty archive is not a representable in all output
formats, e.g. tar archives.
author | Joerg Sonnenberger <joerg@bec.de> |
---|---|
date | Wed, 15 Nov 2023 22:11:34 +0100 |
parents | 454feddab720 |
children | 607e94e01851 |
line wrap: on
line diff
--- a/mercurial/hgweb/webcommands.py Thu Sep 05 13:37:24 2024 +0200 +++ b/mercurial/hgweb/webcommands.py Wed Nov 15 22:11:34 2023 +0100 @@ -1283,35 +1283,46 @@ mimetype, artype, extension, encoding = webutil.archivespecs[type_] - web.res.headers[b'Content-Type'] = mimetype - web.res.headers[b'Content-Disposition'] = b'attachment; filename=%s%s' % ( - name, - extension, - ) - - if encoding: - web.res.headers[b'Content-Encoding'] = encoding - - web.res.setbodywillwrite() - if list(web.res.sendresponse()): - raise error.ProgrammingError( - b'sendresponse() should not emit data if writing later' - ) - if web.req.method == b'HEAD': return [] - bodyfh = web.res.getbodyfile() + def open_archive(): + """Open the output "file" for the archiver. + + This function starts the streaming response. Error reporting + after this point will result in short writes without proper + diagnostics to the client. + """ + web.res.headers[b'Content-Type'] = mimetype + web.res.headers[ + b'Content-Disposition' + ] = b'attachment; filename=%s%s' % ( + name, + extension, + ) - archival.archive( + if encoding: + web.res.headers[b'Content-Encoding'] = encoding + + web.res.setbodywillwrite() + if list(web.res.sendresponse()): + raise error.ProgrammingError( + b'sendresponse() should not emit data if writing later' + ) + + return web.res.getbodyfile() + + total = archival.archive( web.repo, - bodyfh, + open_archive, cnode, artype, prefix=name, match=match, subrepos=web.configbool(b"web", b"archivesubrepos"), ) + if total == 0: + raise ErrorResponse(HTTP_NOT_FOUND, b'no files found in changeset') return []