Open a file in a safe way and return an instance of :exc:`HTTPResponse` that can be sent back to the client. :param filename: Name or path of the file to send, relative to ``root``. :param root: Root path for file lookups. Should be an absolute directory path.
(filename, root,
mimetype=True,
download=False,
charset='UTF-8',
etag=None,
headers=None)
| 2827 | |
| 2828 | |
| 2829 | def static_file(filename, root, |
| 2830 | mimetype=True, |
| 2831 | download=False, |
| 2832 | charset='UTF-8', |
| 2833 | etag=None, |
| 2834 | headers=None): |
| 2835 | """ Open a file in a safe way and return an instance of :exc:`HTTPResponse` |
| 2836 | that can be sent back to the client. |
| 2837 | |
| 2838 | :param filename: Name or path of the file to send, relative to ``root``. |
| 2839 | :param root: Root path for file lookups. Should be an absolute directory |
| 2840 | path. |
| 2841 | :param mimetype: Provide the content-type header (default: guess from |
| 2842 | file extension) |
| 2843 | :param download: If True, ask the browser to open a `Save as...` dialog |
| 2844 | instead of opening the file with the associated program. You can |
| 2845 | specify a custom filename as a string. If not specified, the |
| 2846 | original filename is used (default: False). |
| 2847 | :param charset: The charset for files with a ``text/*`` mime-type. |
| 2848 | (default: UTF-8) |
| 2849 | :param etag: Provide a pre-computed ETag header. If set to ``False``, |
| 2850 | ETag handling is disabled. (default: auto-generate ETag header) |
| 2851 | :param headers: Additional headers dict to add to the response. |
| 2852 | |
| 2853 | While checking user input is always a good idea, this function provides |
| 2854 | additional protection against malicious ``filename`` parameters from |
| 2855 | breaking out of the ``root`` directory and leaking sensitive information |
| 2856 | to an attacker. |
| 2857 | |
| 2858 | Read-protected files or files outside of the ``root`` directory are |
| 2859 | answered with ``403 Access Denied``. Missing files result in a |
| 2860 | ``404 Not Found`` response. Conditional requests (``If-Modified-Since``, |
| 2861 | ``If-None-Match``) are answered with ``304 Not Modified`` whenever |
| 2862 | possible. ``HEAD`` and ``Range`` requests (used by download managers to |
| 2863 | check or continue partial downloads) are also handled automatically. |
| 2864 | |
| 2865 | """ |
| 2866 | |
| 2867 | root = os.path.join(os.path.abspath(root), '') |
| 2868 | filename = os.path.abspath(os.path.join(root, filename.strip('/\\'))) |
| 2869 | headers = headers.copy() if headers else {} |
| 2870 | |
| 2871 | if not filename.startswith(root): |
| 2872 | return HTTPError(403, "Access denied.") |
| 2873 | if not os.path.exists(filename) or not os.path.isfile(filename): |
| 2874 | return HTTPError(404, "File does not exist.") |
| 2875 | if not os.access(filename, os.R_OK): |
| 2876 | return HTTPError(403, "You do not have permission to access this file.") |
| 2877 | |
| 2878 | if mimetype is True: |
| 2879 | if download and download is not True: |
| 2880 | mimetype, encoding = mimetypes.guess_type(download) |
| 2881 | else: |
| 2882 | mimetype, encoding = mimetypes.guess_type(filename) |
| 2883 | if encoding: |
| 2884 | headers['Content-Encoding'] = encoding |
| 2885 | |
| 2886 | if mimetype: |
nothing calls this directly
no test coverage detected