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)
| 3225 | |
| 3226 | |
| 3227 | def static_file(filename, root, |
| 3228 | mimetype=True, |
| 3229 | download=False, |
| 3230 | charset='UTF-8', |
| 3231 | etag=None, |
| 3232 | headers=None): |
| 3233 | """ Open a file in a safe way and return an instance of :exc:`HTTPResponse` |
| 3234 | that can be sent back to the client. |
| 3235 | |
| 3236 | :param filename: Name or path of the file to send, relative to ``root``. |
| 3237 | :param root: Root path for file lookups. Should be an absolute directory |
| 3238 | path. |
| 3239 | :param mimetype: Provide the content-type header (default: guess from |
| 3240 | file extension) |
| 3241 | :param download: If True, ask the browser to open a `Save as...` dialog |
| 3242 | instead of opening the file with the associated program. You can |
| 3243 | specify a custom filename as a string. If not specified, the |
| 3244 | original filename is used (default: False). |
| 3245 | :param charset: The charset for files with a ``text/*`` mime-type. |
| 3246 | (default: UTF-8) |
| 3247 | :param etag: Provide a pre-computed ETag header. If set to ``False``, |
| 3248 | ETag handling is disabled. (default: auto-generate ETag header) |
| 3249 | :param headers: Additional headers dict to add to the response. |
| 3250 | |
| 3251 | While checking user input is always a good idea, this function provides |
| 3252 | additional protection against malicious ``filename`` parameters from |
| 3253 | breaking out of the ``root`` directory and leaking sensitive information |
| 3254 | to an attacker. |
| 3255 | |
| 3256 | Read-protected files or files outside of the ``root`` directory are |
| 3257 | answered with ``403 Access Denied``. Missing files result in a |
| 3258 | ``404 Not Found`` response. Conditional requests (``If-Modified-Since``, |
| 3259 | ``If-None-Match``) are answered with ``304 Not Modified`` whenever |
| 3260 | possible. ``HEAD`` and ``Range`` requests (used by download managers to |
| 3261 | check or continue partial downloads) are also handled automatically. |
| 3262 | |
| 3263 | """ |
| 3264 | |
| 3265 | root = os.path.join(os.path.abspath(root), '') |
| 3266 | filename = os.path.abspath(os.path.join(root, filename.strip('/\\'))) |
| 3267 | headers = headers.copy() if headers else {} |
| 3268 | |
| 3269 | if not filename.startswith(root): |
| 3270 | return HTTPError(403, "Access denied.") |
| 3271 | if not os.path.exists(filename) or not os.path.isfile(filename): |
| 3272 | return HTTPError(404, "File does not exist.") |
| 3273 | if not os.access(filename, os.R_OK): |
| 3274 | return HTTPError(403, "You do not have permission to access this file.") |
| 3275 | |
| 3276 | if mimetype is True: |
| 3277 | if download and download is not True: |
| 3278 | mimetype, encoding = mimetypes.guess_type(download) |
| 3279 | else: |
| 3280 | mimetype, encoding = mimetypes.guess_type(filename) |
| 3281 | if encoding: |
| 3282 | headers['Content-Encoding'] = encoding |
| 3283 | |
| 3284 | if mimetype: |
nothing calls this directly
no test coverage detected
searching dependent graphs…