Validate and return the absolute path. ``root`` is the configured path for the `StaticFileHandler`, and ``path`` is the result of `get_absolute_path` This is an instance method called during request processing, so it may raise `HTTPError` or use methods like
(self, root: str, absolute_path: str)
| 2766 | return abspath |
| 2767 | |
| 2768 | def validate_absolute_path(self, root: str, absolute_path: str) -> Optional[str]: |
| 2769 | """Validate and return the absolute path. |
| 2770 | |
| 2771 | ``root`` is the configured path for the `StaticFileHandler`, |
| 2772 | and ``path`` is the result of `get_absolute_path` |
| 2773 | |
| 2774 | This is an instance method called during request processing, |
| 2775 | so it may raise `HTTPError` or use methods like |
| 2776 | `RequestHandler.redirect` (return None after redirecting to |
| 2777 | halt further processing). This is where 404 errors for missing files |
| 2778 | are generated. |
| 2779 | |
| 2780 | This method may modify the path before returning it, but note that |
| 2781 | any such modifications will not be understood by `make_static_url`. |
| 2782 | |
| 2783 | In instance methods, this method's result is available as |
| 2784 | ``self.absolute_path``. |
| 2785 | |
| 2786 | .. versionadded:: 3.1 |
| 2787 | """ |
| 2788 | # os.path.abspath strips a trailing /. |
| 2789 | # We must add it back to `root` so that we only match files |
| 2790 | # in a directory named `root` instead of files starting with |
| 2791 | # that prefix. |
| 2792 | root = os.path.abspath(root) |
| 2793 | if not root.endswith(os.path.sep): |
| 2794 | # abspath always removes a trailing slash, except when |
| 2795 | # root is '/'. This is an unusual case, but several projects |
| 2796 | # have independently discovered this technique to disable |
| 2797 | # Tornado's path validation and (hopefully) do their own, |
| 2798 | # so we need to support it. |
| 2799 | root += os.path.sep |
| 2800 | # The trailing slash also needs to be temporarily added back |
| 2801 | # the requested path so a request to root/ will match. |
| 2802 | if not (absolute_path + os.path.sep).startswith(root): |
| 2803 | raise HTTPError(403, "%s is not in root static directory", self.path) |
| 2804 | if os.path.isdir(absolute_path) and self.default_filename is not None: |
| 2805 | # need to look at the request.path here for when path is empty |
| 2806 | # but there is some prefix to the path that was already |
| 2807 | # trimmed by the routing |
| 2808 | if not self.request.path.endswith("/"): |
| 2809 | self.redirect(self.request.path + "/", permanent=True) |
| 2810 | return None |
| 2811 | absolute_path = os.path.join(absolute_path, self.default_filename) |
| 2812 | if not os.path.exists(absolute_path): |
| 2813 | raise HTTPError(404) |
| 2814 | if not os.path.isfile(absolute_path): |
| 2815 | raise HTTPError(403, "%s is not a file", self.path) |
| 2816 | return absolute_path |
| 2817 | |
| 2818 | @classmethod |
| 2819 | def get_content( |