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