async def get_response(self, path: str, scope: Scope) -> Response: """ Returns an HTTP response, given the incoming path, method and request headers. """ if scope["method"] not in ("GET", "HEAD"): return PlainTextResponse("Method Not Allowed", status_code=405) full_path, stat_result = await self.lookup_path(path) if stat_result and stat.S_ISREG(stat_result.st_mode): # We have a static file to serve. return self.file_response(full_path, stat_result, scope) elif stat_result and stat.S_ISDIR(stat_result.st_mode) and self.html: # We're in HTML mode, and have got a directory URL. # Check if we have 'index.html' file to serve. index_path = os.path.join(path, "index.html") full_path, stat_result = await self.lookup_path(index_path) if stat_result is not None and stat.S_ISREG(stat_result.st_mode): if not scope["path"].endswith("/"): # Directory URLs should redirect to always end in "/". url = URL(scope=scope) url = url.replace(path=url.path + "/") return RedirectResponse(url=url) return self.file_response(full_path, stat_result, scope) if self.html: # Check for '404.html' if we're in HTML mode. full_path, stat_result = await self.lookup_path("404.html") if stat_result is not None and stat.S_ISREG(stat_result.st_mode): return self.file_response( full_path, stat_result, scope, status_code=404 ) return PlainTextResponse("Not Found", status_code=404)
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if self.allow_any or scope["type"] not in ( "http", "websocket", ): # pragma: no cover await self.app(scope, receive, send) return headers = Headers(scope=scope) host = headers.get("host", "").split(":")[0] is_valid_host = False found_www_redirect = False for pattern in self.allowed_hosts: if host == pattern or ( pattern.startswith("*") and host.endswith(pattern[1:]) ): is_valid_host = True break elif "www." + host == pattern: found_www_redirect = True if is_valid_host: await self.app(scope, receive, send) else: response: Response if found_www_redirect and self.www_redirect: url = URL(scope=scope) redirect_url = url.replace(netloc="www." + url.netloc) response = RedirectResponse(url=str(redirect_url)) else: response = PlainTextResponse("Invalid host header", status_code=400) await response(scope, receive, send)
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: scope["app"] = self if scope["type"] in ("http", "websocket"): # Handle some special routes url = URL(scope=scope) response: typing.Optional[Response] = None # Force jump to https/wss if Config().FORCE_SSL and scope["scheme"] in ("http", "ws"): redirect_scheme = {"http": "https", "ws": "wss"}[url.scheme] netloc = url.hostname if url.port in (80, 443) else url.netloc url = url.replace(scheme=redirect_scheme, netloc=netloc) response = RedirectResponse( url, status_code=301) # for SEO, status code must be 301 if url.path == "/favicon.ico": if os.path.exists(os.path.normpath("favicon.ico")): response = FileResponse("favicon.ico") if response is not None: await response(scope, receive, send) return await self.asgiapp(scope, receive, send)
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: handler = getattr(self, scope["type"]) url = URL(scope=scope) if url.path.endswith("/index"): handler = RedirectResponse( url.replace(path=url.path[:-len("/index")]), status_code=301, ) elif "_" in url.path and not self.allow_underline: handler = RedirectResponse( url.replace(path=url.path.replace("_", "-")), status_code=301, ) await handler(scope, receive, send)
def __call__(self, scope: Scope) -> ASGIInstance: if scope["type"] in ("http", "websocket") and scope["scheme"] in ("http", "ws"): redirect_scheme = {"http": "https", "ws": "wss"}[scope["scheme"]] url = URL(scope=scope) url = url.replace(scheme=redirect_scheme, netloc=url.hostname) return RedirectResponse(url, status_code=301) return self.app(scope)
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] in ("http", "websocket") and scope["scheme"] in ("http", "ws"): url = URL(scope=scope) redirect_scheme = {"http": "https", "ws": "wss"}[url.scheme] netloc = url.hostname if url.port in (80, 443) else url.netloc url = url.replace(scheme=redirect_scheme, netloc=netloc) response = RedirectResponse(url, status_code=307) await response(scope, receive, send) else: await self.app(scope, receive, send)
def test_url(): u = URL("https://example.org:123/path/to/somewhere?abc=123#anchor") assert u.scheme == "https" assert u.hostname == "example.org" assert u.port == 123 assert u.netloc == "example.org:123" assert u.username is None assert u.password is None assert u.path == "/path/to/somewhere" assert u.query == "abc=123" assert u.fragment == "anchor" new = u.replace(scheme="http") assert new == "http://example.org:123/path/to/somewhere?abc=123#anchor" assert new.scheme == "http" new = u.replace(port=None) assert new == "https://example.org/path/to/somewhere?abc=123#anchor" assert new.port is None new = u.replace(hostname="example.com") assert new == "https://example.com:123/path/to/somewhere?abc=123#anchor" assert new.hostname == "example.com"
def __call__(self, scope: Scope) -> ASGIInstance: if scope["type"] in ("http"): host = None for key, value in scope["headers"]: if key == b"host": host = value.decode("latin-1") break if host and not host.startswith("www."): url = URL(scope=scope) url = url.replace(hostname=f"www.{host}") return RedirectResponse(url, status_code=301) return self.app(scope)
async def get_response(self, path: str, scope: Scope) -> Response: """ Returns an HTTP response, given the incoming path, method and request headers. """ if scope["method"] not in ("GET", "HEAD"): raise HTTPException(status_code=405) try: full_path, stat_result = await anyio.to_thread.run_sync( self.lookup_path, path) except PermissionError: raise HTTPException(status_code=401) except OSError: raise if stat_result and stat.S_ISREG(stat_result.st_mode): # We have a static file to serve. return self.file_response(full_path, stat_result, scope) elif stat_result and stat.S_ISDIR(stat_result.st_mode) and self.html: # We're in HTML mode, and have got a directory URL. # Check if we have 'index.html' file to serve. index_path = os.path.join(path, "index.html") full_path, stat_result = await anyio.to_thread.run_sync( self.lookup_path, index_path) if stat_result is not None and stat.S_ISREG(stat_result.st_mode): if not scope["path"].endswith("/"): # Directory URLs should redirect to always end in "/". url = URL(scope=scope) url = url.replace(path=url.path + "/") return RedirectResponse(url=url) return self.file_response(full_path, stat_result, scope) if self.html: # Check for '404.html' if we're in HTML mode. full_path, stat_result = await anyio.to_thread.run_sync( self.lookup_path, "404.html") if stat_result and stat.S_ISREG(stat_result.st_mode): return FileResponse( full_path, stat_result=stat_result, method=scope["method"], status_code=404, ) raise HTTPException(status_code=404)
def __call__(self, scope: Scope) -> ASGIInstance: if scope["type"] in ("http", "websocket") and not self.allow_any: headers = Headers(scope=scope) host = headers.get("host", "").split(":")[0] found_www_redirect = False for pattern in self.allowed_hosts: if host == pattern or (pattern.startswith("*") and host.endswith(pattern[1:])): break elif "www." + host == pattern: found_www_redirect = True else: if found_www_redirect and self.www_redirect: url = URL(scope=scope) redirect_url = url.replace(netloc="www." + url.netloc) return RedirectResponse(url=str(redirect_url)) return PlainTextResponse("Invalid host header", status_code=400) return self.app(scope)