diff --git a/docs/request_data.md b/docs/request_data.md index 8891d07f..7506df18 100644 --- a/docs/request_data.md +++ b/docs/request_data.md @@ -16,7 +16,7 @@ See request.py for more information ```python from sanic import Sanic -from sanic.response import json, text +from sanic.response import json, text, file @app.route("/json") def post_json(request): @@ -46,4 +46,11 @@ def query_string(request): @app.route("/users", methods=["POST",]) def create_user(request): return text("You are trying to create a user with the following POST: %s" % request.body) + + +@app.route("/file/", methods=["GET",]) +def download_a_file(request, file_id): + def find_path_by_id(file_id): + return "/path/to/file.ext" + return file(find_path_by_id(file_id), force_download=True) ``` diff --git a/sanic/response.py b/sanic/response.py index d0e64cea..88925035 100644 --- a/sanic/response.py +++ b/sanic/response.py @@ -153,13 +153,25 @@ def html(body, status=200, headers=None): content_type="text/html; charset=utf-8") -async def file(location, mime_type=None, headers=None): +async def file(location, mime_type=None, headers=None, force_download=False): + """ + Produces a response that serves file content. + :param location: Absolute file path + :param mime_type: File MIME type + :param headers: List of HTTP headers + :param force_download: if `True` immediately prompt the user to save + the file directly to the user's disk, without opening it in the browser + """ filename = path.split(location)[-1] async with open_async(location, mode='rb') as _file: out_stream = await _file.read() - - mime_type = mime_type or guess_type(filename)[0] or 'text/plain' + # Do not attempt to render file in browser + if force_download is True: + headers["Content-Disposition"] = "attachment; filename=%s" % filename + mime_type = 'application/octet-stream' + else: + mime_type = mime_type or guess_type(filename)[0] or 'text/plain' return HTTPResponse(status=200, headers=headers,