Returns an HTTP response, given the incoming path, method and request headers.
(self, path: str, scope: Scope)
| 113 | return os.path.normpath(os.path.join(*route_path.split("/"))) |
| 114 | |
| 115 | async def get_response(self, path: str, scope: Scope) -> Response: |
| 116 | """ |
| 117 | Returns an HTTP response, given the incoming path, method and request headers. |
| 118 | """ |
| 119 | if scope["method"] not in ("GET", "HEAD"): |
| 120 | raise HTTPException(status_code=405) |
| 121 | |
| 122 | try: |
| 123 | full_path, stat_result = await anyio.to_thread.run_sync(self.lookup_path, path) |
| 124 | except PermissionError: |
| 125 | raise HTTPException(status_code=401) |
| 126 | except OSError as exc: |
| 127 | # Filename is too long, so it can't be a valid static file. |
| 128 | if exc.errno == errno.ENAMETOOLONG: |
| 129 | raise HTTPException(status_code=404) |
| 130 | |
| 131 | raise exc |
| 132 | except ValueError: |
| 133 | # Null bytes or other invalid characters in the path. |
| 134 | raise HTTPException(status_code=404) |
| 135 | |
| 136 | if stat_result and stat.S_ISREG(stat_result.st_mode): |
| 137 | # We have a static file to serve. |
| 138 | return self.file_response(full_path, stat_result, scope) |
| 139 | |
| 140 | elif stat_result and stat.S_ISDIR(stat_result.st_mode) and self.html: |
| 141 | # We're in HTML mode, and have got a directory URL. |
| 142 | # Check if we have 'index.html' file to serve. |
| 143 | index_path = os.path.join(path, "index.html") |
| 144 | full_path, stat_result = await anyio.to_thread.run_sync(self.lookup_path, index_path) |
| 145 | if stat_result is not None and stat.S_ISREG(stat_result.st_mode): |
| 146 | if not scope["path"].endswith("/"): |
| 147 | # Directory URLs should redirect to always end in "/". |
| 148 | url = URL(scope=scope) |
| 149 | url = url.replace(path=url.path + "/") |
| 150 | return RedirectResponse(url=url) |
| 151 | return self.file_response(full_path, stat_result, scope) |
| 152 | |
| 153 | if self.html: |
| 154 | # Check for '404.html' if we're in HTML mode. |
| 155 | full_path, stat_result = await anyio.to_thread.run_sync(self.lookup_path, "404.html") |
| 156 | if stat_result and stat.S_ISREG(stat_result.st_mode): |
| 157 | return FileResponse(full_path, stat_result=stat_result, status_code=404) |
| 158 | raise HTTPException(status_code=404) |
| 159 | |
| 160 | def lookup_path(self, path: str) -> tuple[str, os.stat_result | None]: |
| 161 | # Reject absolute paths so they cannot escape the served directory. |
no test coverage detected