diff --git a/frappe/utils/response.py b/frappe/utils/response.py index 4265ac64e9..b576277ae3 100644 --- a/frappe/utils/response.py +++ b/frappe/utils/response.py @@ -19,7 +19,6 @@ import werkzeug.utils from werkzeug.exceptions import Forbidden, NotFound from werkzeug.local import LocalProxy from werkzeug.wrappers import Response -from werkzeug.wsgi import wrap_file import frappe import frappe.model.document @@ -306,26 +305,26 @@ def send_private_file(path: str) -> Response: response = Response() response.headers["X-Accel-Redirect"] = quote(frappe.utils.encode(path)) response.headers["Cache-Control"] = "private,max-age=3600,stale-while-revalidate=86400" + response.headers["Accept-Ranges"] = "bytes" else: filepath = frappe.utils.get_site_path(path) - try: - f = open(filepath, "rb") - except OSError: + if not os.path.exists(filepath): raise NotFound - response = Response(wrap_file(frappe.local.request.environ, f), direct_passthrough=True) + mimetype = mimetypes.guess_type(filename)[0] or "application/octet-stream" - # no need for content disposition and force download. let browser handle its opening. - # Except for those that can be injected with scripts. + extension = os.path.splitext(path)[1] + blacklist = [".svg", ".html", ".htm", ".xml"] + as_attachment = extension.lower() in blacklist - extension = os.path.splitext(path)[1] - blacklist = [".svg", ".html", ".htm", ".xml"] + send_kwargs = dict(mimetype=mimetype, conditional=True, as_attachment=as_attachment) + environ = frappe.local.request.environ - if extension.lower() in blacklist: - response.headers.add("Content-Disposition", "attachment", filename=filename) - - response.mimetype = mimetypes.guess_type(filename)[0] or "application/octet-stream" + if as_attachment: + response = werkzeug.utils.send_file(filepath, environ, download_name=filename, **send_kwargs) + else: + response = werkzeug.utils.send_file(filepath, environ, **send_kwargs) return response