| 26 | |
| 27 | |
| 28 | class URL: |
| 29 | def __init__( |
| 30 | self, |
| 31 | url: str = "", |
| 32 | scope: Scope | None = None, |
| 33 | **components: Any, |
| 34 | ) -> None: |
| 35 | if scope is not None: |
| 36 | assert not url, 'Cannot set both "url" and "scope".' |
| 37 | assert not components, 'Cannot set both "scope" and "**components".' |
| 38 | scheme = scope.get("scheme", "http") |
| 39 | server = scope.get("server", None) |
| 40 | path = scope["path"] |
| 41 | query_string = scope.get("query_string", b"") |
| 42 | |
| 43 | host_header = None |
| 44 | for key, value in scope["headers"]: |
| 45 | if key == b"host": |
| 46 | host_header = value.decode("latin-1") |
| 47 | break |
| 48 | |
| 49 | if host_header is not None and _HOST_RE.fullmatch(host_header): |
| 50 | netloc = host_header |
| 51 | elif server is not None: |
| 52 | host, port = server |
| 53 | default_port = {"http": 80, "https": 443, "ws": 80, "wss": 443}[scheme] |
| 54 | netloc = host if port == default_port else f"{host}:{port}" |
| 55 | else: |
| 56 | netloc = None |
| 57 | |
| 58 | query = query_string.decode() |
| 59 | if netloc is not None: |
| 60 | url = SplitResult(scheme=scheme, netloc=netloc, path=path, query=query, fragment="").geturl() |
| 61 | else: |
| 62 | url = f"{path}?{query}" if query else path |
| 63 | elif components: |
| 64 | assert not url, 'Cannot set both "url" and "**components".' |
| 65 | url = URL("").replace(**components).components.geturl() |
| 66 | |
| 67 | self._url = url |
| 68 | |
| 69 | @property |
| 70 | def components(self) -> SplitResult: |
| 71 | if not hasattr(self, "_components"): |
| 72 | self._components = urlsplit(self._url) |
| 73 | return self._components |
| 74 | |
| 75 | @property |
| 76 | def scheme(self) -> str: |
| 77 | return self.components.scheme |
| 78 | |
| 79 | @property |
| 80 | def netloc(self) -> str: |
| 81 | return self.components.netloc |
| 82 | |
| 83 | @property |
| 84 | def path(self) -> str: |
| 85 | return self.components.path |
no outgoing calls